Migrated to null safety. Moved package universal_ui to universal_ui.dart since there was no null safe version available at this time.

pull/101/head
John Wehrle 4 years ago
parent 701c56c312
commit ecfc5adc3e
  1. 3
      app/android/build.gradle
  2. 1
      app/ios/Flutter/Debug.xcconfig
  3. 1
      app/ios/Flutter/Release.xcconfig
  4. 16
      app/lib/pages/home_page.dart
  5. 16
      app/lib/widgets/demo_scaffold.dart
  6. 30
      app/lib/widgets/field.dart
  7. 50
      app/pubspec.lock
  8. 2
      app/pubspec.yaml
  9. 114
      lib/models/documents/attribute.dart
  10. 14
      lib/models/documents/document.dart
  11. 12
      lib/models/documents/nodes/block.dart
  12. 18
      lib/models/documents/nodes/container.dart
  13. 6
      lib/models/documents/nodes/embed.dart
  14. 71
      lib/models/documents/nodes/leaf.dart
  15. 90
      lib/models/documents/nodes/line.dart
  16. 17
      lib/models/documents/nodes/node.dart
  17. 12
      lib/models/documents/style.dart
  18. 119
      lib/models/quill_delta.dart
  19. 48
      lib/models/rules/delete.dart
  20. 51
      lib/models/rules/format.dart
  21. 136
      lib/models/rules/insert.dart
  22. 17
      lib/models/rules/rule.dart
  23. 4
      lib/universal_ui/fake_ui.dart
  24. 9
      lib/universal_ui/real_ui.dart
  25. 20
      lib/universal_ui/universal_ui.dart
  26. 7
      lib/utils/diff_delta.dart
  27. 6
      lib/widgets/box.dart
  28. 17
      lib/widgets/controller.dart
  29. 61
      lib/widgets/cursor.dart
  30. 60
      lib/widgets/default_styles.dart
  31. 35
      lib/widgets/delegate.dart
  32. 273
      lib/widgets/editor.dart
  33. 2
      lib/widgets/image.dart
  34. 7
      lib/widgets/keyboard_listener.dart
  35. 71
      lib/widgets/proxy.dart
  36. 279
      lib/widgets/raw_editor.dart
  37. 8
      lib/widgets/responsive_widget.dart
  38. 185
      lib/widgets/text_block.dart
  39. 265
      lib/widgets/text_line.dart
  40. 227
      lib/widgets/text_selection.dart
  41. 281
      lib/widgets/toolbar.dart
  42. 43
      pubspec.lock
  43. 12
      pubspec.yaml

@ -5,7 +5,8 @@ buildscript {
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:3.6.3' //classpath 'com.android.tools.build:gradle:3.6.3'
classpath 'com.android.tools.build:gradle:4.1.0'
} }
} }

@ -1 +1,2 @@
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
#include "Generated.xcconfig" #include "Generated.xcconfig"

@ -1 +1,2 @@
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
#include "Generated.xcconfig" #include "Generated.xcconfig"

@ -23,7 +23,7 @@ class HomePage extends StatefulWidget {
} }
class _HomePageState extends State<HomePage> { class _HomePageState extends State<HomePage> {
QuillController _controller; QuillController? _controller;
final FocusNode _focusNode = FocusNode(); final FocusNode _focusNode = FocusNode();
@override @override
@ -75,15 +75,15 @@ class _HomePageState extends State<HomePage> {
focusNode: FocusNode(), focusNode: FocusNode(),
onKey: (RawKeyEvent event) { onKey: (RawKeyEvent event) {
if (event.data.isControlPressed && event.character == 'b') { if (event.data.isControlPressed && event.character == 'b') {
if (_controller if (_controller!
.getSelectionStyle() .getSelectionStyle()
.attributes .attributes
.keys .keys
.contains("bold")) { .contains("bold")) {
_controller _controller!
.formatSelection(Attribute.clone(Attribute.bold, null)); .formatSelection(Attribute.clone(Attribute.bold, null));
} else { } else {
_controller.formatSelection(Attribute.bold); _controller!.formatSelection(Attribute.bold);
print("not bold"); print("not bold");
} }
} }
@ -104,7 +104,7 @@ class _HomePageState extends State<HomePage> {
color: Colors.white, color: Colors.white,
padding: const EdgeInsets.only(left: 16.0, right: 16.0), padding: const EdgeInsets.only(left: 16.0, right: 16.0),
child: QuillEditor( child: QuillEditor(
controller: _controller, controller: _controller!,
scrollController: ScrollController(), scrollController: ScrollController(),
scrollable: true, scrollable: true,
focusNode: _focusNode, focusNode: _focusNode,
@ -135,12 +135,12 @@ class _HomePageState extends State<HomePage> {
child: Container( child: Container(
padding: EdgeInsets.symmetric(vertical: 16, horizontal: 8), padding: EdgeInsets.symmetric(vertical: 16, horizontal: 8),
child: QuillToolbar.basic( child: QuillToolbar.basic(
controller: _controller, controller: _controller!,
onImagePickCallback: _onImagePickCallback), onImagePickCallback: _onImagePickCallback),
)) ))
: Container( : Container(
child: QuillToolbar.basic( child: QuillToolbar.basic(
controller: _controller, controller: _controller!,
onImagePickCallback: _onImagePickCallback), onImagePickCallback: _onImagePickCallback),
), ),
], ],
@ -150,7 +150,7 @@ class _HomePageState extends State<HomePage> {
// Renders the image picked by imagePicker from local file storage // Renders the image picked by imagePicker from local file storage
// You can also upload the picked image to any server (eg : AWS s3 or Firebase) and then return the uploaded image URL // You can also upload the picked image to any server (eg : AWS s3 or Firebase) and then return the uploaded image URL
Future<String> _onImagePickCallback(File file) async { Future<String?> _onImagePickCallback(File? file) async {
if (file == null) return null; if (file == null) return null;
// Copies the picked file from temporary cache to applications directory // Copies the picked file from temporary cache to applications directory
Directory appDocDir = await getApplicationDocumentsDirectory(); Directory appDocDir = await getApplicationDocumentsDirectory();

@ -14,14 +14,14 @@ class DemoScaffold extends StatefulWidget {
/// Filename of the document to load into the editor. /// Filename of the document to load into the editor.
final String documentFilename; final String documentFilename;
final DemoContentBuilder builder; final DemoContentBuilder builder;
final List<Widget> actions; final List<Widget>? actions;
final Widget floatingActionButton; final Widget? floatingActionButton;
final bool showToolbar; final bool showToolbar;
const DemoScaffold({ const DemoScaffold({
Key key, Key? key,
@required this.documentFilename, required this.documentFilename,
@required this.builder, required this.builder,
this.actions, this.actions,
this.showToolbar = true, this.showToolbar = true,
this.floatingActionButton, this.floatingActionButton,
@ -33,7 +33,7 @@ class DemoScaffold extends StatefulWidget {
class _DemoScaffoldState extends State<DemoScaffold> { class _DemoScaffoldState extends State<DemoScaffold> {
final _scaffoldKey = GlobalKey<ScaffoldState>(); final _scaffoldKey = GlobalKey<ScaffoldState>();
QuillController _controller; QuillController? _controller;
bool _loading = false; bool _loading = false;
@ -92,13 +92,13 @@ class _DemoScaffoldState extends State<DemoScaffold> {
), ),
title: _loading || widget.showToolbar == false title: _loading || widget.showToolbar == false
? null ? null
: QuillToolbar.basic(controller: _controller), : QuillToolbar.basic(controller: _controller!),
actions: actions, actions: actions,
), ),
floatingActionButton: widget.floatingActionButton, floatingActionButton: widget.floatingActionButton,
body: _loading body: _loading
? Center(child: Text('Loading...')) ? Center(child: Text('Loading...'))
: widget.builder(context, _controller), : widget.builder(context, _controller!),
); );
} }
} }

@ -14,22 +14,22 @@ class QuillField extends StatefulWidget {
final bool showCursor; final bool showCursor;
final bool readOnly; final bool readOnly;
final bool enableInteractiveSelection; final bool enableInteractiveSelection;
final double minHeight; final double? minHeight;
final double maxHeight; final double? maxHeight;
final bool expands; final bool expands;
final TextCapitalization textCapitalization; final TextCapitalization textCapitalization;
final Brightness keyboardAppearance; final Brightness keyboardAppearance;
final ScrollPhysics scrollPhysics; final ScrollPhysics? scrollPhysics;
final ValueChanged<String> onLaunchUrl; final ValueChanged<String>? onLaunchUrl;
final InputDecoration decoration; final InputDecoration? decoration;
final Widget toolbar; final Widget? toolbar;
final EmbedBuilder embedBuilder; final EmbedBuilder? embedBuilder;
QuillField({ QuillField({
Key key, Key? key,
@required this.controller, required this.controller,
this.focusNode, required this.focusNode,
this.scrollController, required this.scrollController,
this.scrollable = true, this.scrollable = true,
this.padding = EdgeInsets.zero, this.padding = EdgeInsets.zero,
this.autofocus = false, this.autofocus = false,
@ -53,7 +53,7 @@ class QuillField extends StatefulWidget {
} }
class _QuillFieldState extends State<QuillField> { class _QuillFieldState extends State<QuillField> {
bool _focused; bool? _focused;
void _editorFocusChanged() { void _editorFocusChanged() {
setState(() { setState(() {
@ -105,8 +105,8 @@ class _QuillFieldState extends State<QuillField> {
children: [ children: [
child, child,
Visibility( Visibility(
child: widget.toolbar, child: widget.toolbar!,
visible: _focused, visible: _focused!,
maintainSize: true, maintainSize: true,
maintainAnimation: true, maintainAnimation: true,
maintainState: true, maintainState: true,
@ -118,7 +118,7 @@ class _QuillFieldState extends State<QuillField> {
return AnimatedBuilder( return AnimatedBuilder(
animation: animation:
Listenable.merge(<Listenable>[widget.focusNode, widget.controller]), Listenable.merge(<Listenable>[widget.focusNode, widget.controller]),
builder: (BuildContext context, Widget child) { builder: (BuildContext context, Widget? child) {
return InputDecorator( return InputDecorator(
decoration: _getEffectiveDecoration(), decoration: _getEffectiveDecoration(),
isFocused: widget.focusNode.hasFocus, isFocused: widget.focusNode.hasFocus,

@ -43,27 +43,20 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.15.0" version: "1.15.0"
convert:
dependency: transitive
description:
name: convert
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.1"
crypto: crypto:
dependency: transitive dependency: transitive
description: description:
name: crypto name: crypto
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.1.5" version: "3.0.0"
csslib: csslib:
dependency: transitive dependency: transitive
description: description:
name: csslib name: csslib
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.16.2" version: "0.17.0"
cupertino_icons: cupertino_icons:
dependency: "direct main" dependency: "direct main"
description: description:
@ -105,7 +98,7 @@ packages:
name: filesystem_picker name: filesystem_picker
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.0.4" version: "2.0.0-nullsafety.0"
flutter: flutter:
dependency: "direct main" dependency: "direct main"
description: flutter description: flutter
@ -117,7 +110,7 @@ packages:
name: flutter_colorpicker name: flutter_colorpicker
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.3.5" version: "0.4.0-nullsafety.0"
flutter_keyboard_visibility: flutter_keyboard_visibility:
dependency: transitive dependency: transitive
description: description:
@ -169,7 +162,7 @@ packages:
name: html name: html
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.14.0+4" version: "0.15.0"
http: http:
dependency: transitive dependency: transitive
description: description:
@ -302,14 +295,7 @@ packages:
name: quiver name: quiver
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.1.5" version: "3.0.0"
quiver_hashcode:
dependency: transitive
description:
name: quiver_hashcode
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.0"
sky_engine: sky_engine:
dependency: transitive dependency: transitive
description: flutter description: flutter
@ -349,7 +335,7 @@ packages:
name: string_validator name: string_validator
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.1.4" version: "0.3.0"
term_glyph: term_glyph:
dependency: transitive dependency: transitive
description: description:
@ -370,7 +356,7 @@ packages:
name: tuple name: tuple
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.0.3" version: "2.0.0"
typed_data: typed_data:
dependency: transitive dependency: transitive
description: description:
@ -384,21 +370,14 @@ packages:
name: universal_html name: universal_html
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.2.4" version: "2.0.4"
universal_io: universal_io:
dependency: transitive dependency: transitive
description: description:
name: universal_io name: universal_io
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.0.2" version: "2.0.1"
universal_ui:
dependency: transitive
description:
name: universal_ui
url: "https://pub.dartlang.org"
source: hosted
version: "0.0.8"
url_launcher: url_launcher:
dependency: transitive dependency: transitive
description: description:
@ -462,13 +441,6 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.2.0" version: "0.2.0"
zone_local:
dependency: transitive
description:
name: zone_local
url: "https://pub.dartlang.org"
source: hosted
version: "0.1.2"
sdks: sdks:
dart: ">=2.12.0 <3.0.0" dart: ">=2.12.0 <3.0.0"
flutter: ">=1.22.0" flutter: ">=1.24.0-10.2.pre"

@ -18,7 +18,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
version: 1.0.0+1 version: 1.0.0+1
environment: environment:
sdk: ">=2.7.0 <3.0.0" sdk: ">=2.12.0 <3.0.0"
dependencies: dependencies:
flutter: flutter:

@ -8,33 +8,33 @@ enum AttributeScope {
} }
class Attribute<T> { class Attribute<T> {
final String key; final String? key;
final AttributeScope scope; final AttributeScope? scope;
final T value; final T? value;
Attribute(this.key, this.scope, this.value); Attribute(this.key, this.scope, this.value);
static final Map<String, Attribute> _registry = { static final Map<String, Attribute> _registry = {
Attribute.bold.key: Attribute.bold, Attribute.bold.key!: Attribute.bold,
Attribute.italic.key: Attribute.italic, Attribute.italic.key!: Attribute.italic,
Attribute.underline.key: Attribute.underline, Attribute.underline.key!: Attribute.underline,
Attribute.strikeThrough.key: Attribute.strikeThrough, Attribute.strikeThrough.key!: Attribute.strikeThrough,
Attribute.font.key: Attribute.font, Attribute.font.key!: Attribute.font,
Attribute.size.key: Attribute.size, Attribute.size.key!: Attribute.size,
Attribute.link.key: Attribute.link, Attribute.link.key!: Attribute.link,
Attribute.color.key: Attribute.color, Attribute.color.key!: Attribute.color,
Attribute.background.key: Attribute.background, Attribute.background.key!: Attribute.background,
Attribute.placeholder.key: Attribute.placeholder, Attribute.placeholder.key!: Attribute.placeholder,
Attribute.header.key: Attribute.header, Attribute.header.key!: Attribute.header,
Attribute.indent.key: Attribute.indent, Attribute.indent.key!: Attribute.indent,
Attribute.align.key: Attribute.align, Attribute.align.key!: Attribute.align,
Attribute.list.key: Attribute.list, Attribute.list.key!: Attribute.list,
Attribute.codeBlock.key: Attribute.codeBlock, Attribute.codeBlock.key!: Attribute.codeBlock,
Attribute.blockQuote.key: Attribute.blockQuote, Attribute.blockQuote.key!: Attribute.blockQuote,
Attribute.width.key: Attribute.width, Attribute.width.key!: Attribute.width,
Attribute.height.key: Attribute.height, Attribute.height.key!: Attribute.height,
Attribute.style.key: Attribute.style, Attribute.style.key!: Attribute.style,
Attribute.token.key: Attribute.token, Attribute.token.key!: Attribute.token,
}; };
static final BoldAttribute bold = BoldAttribute(); static final BoldAttribute bold = BoldAttribute();
@ -78,31 +78,31 @@ class Attribute<T> {
static final TokenAttribute token = TokenAttribute(null); static final TokenAttribute token = TokenAttribute(null);
static final Set<String> inlineKeys = { static final Set<String> inlineKeys = {
Attribute.bold.key, Attribute.bold.key!,
Attribute.italic.key, Attribute.italic.key!,
Attribute.underline.key, Attribute.underline.key!,
Attribute.strikeThrough.key, Attribute.strikeThrough.key!,
Attribute.link.key, Attribute.link.key!,
Attribute.color.key, Attribute.color.key!,
Attribute.background.key, Attribute.background.key!,
Attribute.placeholder.key, Attribute.placeholder.key!,
}; };
static final Set<String> blockKeys = { static final Set<String> blockKeys = {
Attribute.header.key, Attribute.header.key!,
Attribute.indent.key, Attribute.indent.key!,
Attribute.align.key, Attribute.align.key!,
Attribute.list.key, Attribute.list.key!,
Attribute.codeBlock.key, Attribute.codeBlock.key!,
Attribute.blockQuote.key, Attribute.blockQuote.key!,
}; };
static final Set<String> blockKeysExceptHeader = { static final Set<String> blockKeysExceptHeader = {
Attribute.list.key, Attribute.list.key!,
Attribute.indent.key, Attribute.indent.key!,
Attribute.align.key, Attribute.align.key!,
Attribute.codeBlock.key, Attribute.codeBlock.key!,
Attribute.blockQuote.key, Attribute.blockQuote.key!,
}; };
static Attribute<int> get h1 => HeaderAttribute(level: 1); static Attribute<int> get h1 => HeaderAttribute(level: 1);
@ -158,13 +158,13 @@ class Attribute<T> {
bool get isBlockExceptHeader => blockKeysExceptHeader.contains(key); bool get isBlockExceptHeader => blockKeysExceptHeader.contains(key);
Map<String, dynamic> toJson() => <String, dynamic>{key: value}; Map<String, dynamic> toJson() => <String, dynamic>{key!: value};
static Attribute fromKeyValue(String key, dynamic value) { static Attribute fromKeyValue(String key, dynamic value) {
if (!_registry.containsKey(key)) { if (!_registry.containsKey(key)) {
throw ArgumentError.value(key, 'key "$key" not found.'); throw ArgumentError.value(key, 'key "$key" not found.');
} }
Attribute origin = _registry[key]; Attribute origin = _registry[key]!;
Attribute attribute = clone(origin, value); Attribute attribute = clone(origin, value);
return attribute; return attribute;
} }
@ -209,23 +209,23 @@ class StrikeThroughAttribute extends Attribute<bool> {
} }
class FontAttribute extends Attribute<String> { class FontAttribute extends Attribute<String> {
FontAttribute(String val) : super('font', AttributeScope.INLINE, val); FontAttribute(String? val) : super('font', AttributeScope.INLINE, val);
} }
class SizeAttribute extends Attribute<String> { class SizeAttribute extends Attribute<String> {
SizeAttribute(String val) : super('size', AttributeScope.INLINE, val); SizeAttribute(String? val) : super('size', AttributeScope.INLINE, val);
} }
class LinkAttribute extends Attribute<String> { class LinkAttribute extends Attribute<String> {
LinkAttribute(String val) : super('link', AttributeScope.INLINE, val); LinkAttribute(String? val) : super('link', AttributeScope.INLINE, val);
} }
class ColorAttribute extends Attribute<String> { class ColorAttribute extends Attribute<String> {
ColorAttribute(String val) : super('color', AttributeScope.INLINE, val); ColorAttribute(String? val) : super('color', AttributeScope.INLINE, val);
} }
class BackgroundAttribute extends Attribute<String> { class BackgroundAttribute extends Attribute<String> {
BackgroundAttribute(String val) BackgroundAttribute(String? val)
: super('background', AttributeScope.INLINE, val); : super('background', AttributeScope.INLINE, val);
} }
@ -235,19 +235,19 @@ class PlaceholderAttribute extends Attribute<bool> {
} }
class HeaderAttribute extends Attribute<int> { class HeaderAttribute extends Attribute<int> {
HeaderAttribute({int level}) : super('header', AttributeScope.BLOCK, level); HeaderAttribute({int? level}) : super('header', AttributeScope.BLOCK, level);
} }
class IndentAttribute extends Attribute<int> { class IndentAttribute extends Attribute<int> {
IndentAttribute({int level}) : super('indent', AttributeScope.BLOCK, level); IndentAttribute({int? level}) : super('indent', AttributeScope.BLOCK, level);
} }
class AlignAttribute extends Attribute<String> { class AlignAttribute extends Attribute<String> {
AlignAttribute(String val) : super('align', AttributeScope.BLOCK, val); AlignAttribute(String? val) : super('align', AttributeScope.BLOCK, val);
} }
class ListAttribute extends Attribute<String> { class ListAttribute extends Attribute<String> {
ListAttribute(String val) : super('list', AttributeScope.BLOCK, val); ListAttribute(String? val) : super('list', AttributeScope.BLOCK, val);
} }
class CodeBlockAttribute extends Attribute<bool> { class CodeBlockAttribute extends Attribute<bool> {
@ -259,17 +259,17 @@ class BlockQuoteAttribute extends Attribute<bool> {
} }
class WidthAttribute extends Attribute<String> { class WidthAttribute extends Attribute<String> {
WidthAttribute(String val) : super('width', AttributeScope.IGNORE, val); WidthAttribute(String? val) : super('width', AttributeScope.IGNORE, val);
} }
class HeightAttribute extends Attribute<String> { class HeightAttribute extends Attribute<String> {
HeightAttribute(String val) : super('height', AttributeScope.IGNORE, val); HeightAttribute(String? val) : super('height', AttributeScope.IGNORE, val);
} }
class StyleAttribute extends Attribute<String> { class StyleAttribute extends Attribute<String> {
StyleAttribute(String val) : super('style', AttributeScope.IGNORE, val); StyleAttribute(String? val) : super('style', AttributeScope.IGNORE, val);
} }
class TokenAttribute extends Attribute<String> { class TokenAttribute extends Attribute<String> {
TokenAttribute(String val) : super('token', AttributeScope.IGNORE, val); TokenAttribute(String? val) : super('token', AttributeScope.IGNORE, val);
} }

@ -47,7 +47,7 @@ class Document {
assert(index >= 0); assert(index >= 0);
assert(data is String || data is Embeddable); assert(data is String || data is Embeddable);
if (data is Embeddable) { if (data is Embeddable) {
data = (data as Embeddable).toJson(); data = data.toJson();
} else if ((data as String).isEmpty) { } else if ((data as String).isEmpty) {
return Delta(); return Delta();
} }
@ -89,7 +89,7 @@ class Document {
} }
Delta format(int index, int len, Attribute attribute) { Delta format(int index, int len, Attribute attribute) {
assert(index >= 0 && len >= 0 && attribute != null); assert(index >= 0 && len >= 0);
Delta delta = Delta(); Delta delta = Delta();
@ -105,7 +105,7 @@ class Document {
Style collectStyle(int index, int len) { Style collectStyle(int index, int len) {
ChildQuery res = queryChild(index); ChildQuery res = queryChild(index);
return (res.node as Line).collectStyle(res.offset, len); return (res.node as Line).collectStyle(res.offset!, len);
} }
ChildQuery queryChild(int offset) { ChildQuery queryChild(int offset) {
@ -113,8 +113,8 @@ class Document {
if (res.node is Line) { if (res.node is Line) {
return res; return res;
} }
Block block = res.node; Block block = (res.node as Block);
return block.queryChild(res.offset, true); return block.queryChild(res.offset!, true);
} }
compose(Delta delta, ChangeSource changeSource) { compose(Delta delta, ChangeSource changeSource) {
@ -126,7 +126,7 @@ class Document {
delta = _transform(delta); delta = _transform(delta);
Delta originalDelta = toDelta(); Delta originalDelta = toDelta();
for (Operation op in delta.toList()) { for (Operation op in delta.toList()) {
Style style = Style? style =
op.attributes != null ? Style.fromJson(op.attributes) : null; op.attributes != null ? Style.fromJson(op.attributes) : null;
if (op.isInsert) { if (op.isInsert) {
@ -205,7 +205,7 @@ class Document {
if (data is Embeddable) { if (data is Embeddable) {
return data; return data;
} }
return Embeddable.fromJson(data); return Embeddable.fromJson((data as Map<String, dynamic>));
} }
close() { close() {

@ -18,7 +18,7 @@ class Block extends Container<Line> {
@override @override
adjust() { adjust() {
if (isEmpty) { if (isEmpty) {
Node sibling = previous; Node? sibling = previous;
unlink(); unlink();
if (sibling != null) { if (sibling != null) {
sibling.adjust(); sibling.adjust();
@ -27,16 +27,16 @@ class Block extends Container<Line> {
} }
Block block = this; Block block = this;
Node prev = block.previous; Node? prev = block.previous;
// merging it with previous block if style is the same // merging it with previous block if style is the same
if (!block.isFirst && if (!block.isFirst &&
block.previous is Block && block.previous is Block &&
prev.style == block.style) { prev!.style == block.style) {
block.moveChildToNewParent(prev); block.moveChildToNewParent((prev as Container<Node>));
block.unlink(); block.unlink();
block = prev; block = (prev as Block);
} }
Node next = block.next; Node next = block.next!;
// merging it with next block if style is the same // merging it with next block if style is the same
if (!block.isLast && block.next is Block && next.style == block.style) { if (!block.isLast && block.next is Block && next.style == block.style) {
(next as Block).moveChildToNewParent(block); (next as Block).moveChildToNewParent(block);

@ -48,9 +48,9 @@ abstract class Container<T extends Node> extends Node {
return; return;
} }
T last = newParent.isEmpty ? null : newParent.last; T? last = (newParent.isEmpty ? null : newParent.last as T);
while (isNotEmpty) { while (isNotEmpty) {
T child = first; T child = (first as T);
child.unlink(); child.unlink();
newParent.add(child); newParent.add(child);
} }
@ -80,12 +80,12 @@ abstract class Container<T extends Node> extends Node {
int get length => _children.fold(0, (cur, node) => cur + node.length); int get length => _children.fold(0, (cur, node) => cur + node.length);
@override @override
insert(int index, Object data, Style style) { insert(int index, Object data, Style? style) {
assert(index == 0 || (index > 0 && index < length)); assert(index == 0 || (index > 0 && index < length));
if (isNotEmpty) { if (isNotEmpty) {
ChildQuery child = queryChild(index, false); ChildQuery child = queryChild(index, false);
child.node.insert(child.offset, data, style); child.node!.insert(child.offset!, data, style);
return; return;
} }
@ -97,17 +97,17 @@ abstract class Container<T extends Node> extends Node {
} }
@override @override
retain(int index, int length, Style attributes) { retain(int index, int length, Style? attributes) {
assert(isNotEmpty); assert(isNotEmpty);
ChildQuery child = queryChild(index, false); ChildQuery child = queryChild(index, false);
child.node.retain(child.offset, length, attributes); child.node!.retain(child.offset!, length, attributes);
} }
@override @override
delete(int index, int length) { delete(int index, int length) {
assert(isNotEmpty); assert(isNotEmpty);
ChildQuery child = queryChild(index, false); ChildQuery child = queryChild(index, false);
child.node.delete(child.offset, length); child.node!.delete(child.offset!, length);
} }
@override @override
@ -116,9 +116,9 @@ abstract class Container<T extends Node> extends Node {
/// Query of a child in a Container /// Query of a child in a Container
class ChildQuery { class ChildQuery {
final Node node; // null if not found final Node? node; // null if not found
final int offset; final int? offset;
ChildQuery(this.node, this.offset); ChildQuery(this.node, this.offset);
} }

@ -1,13 +1,13 @@
class Embeddable { class Embeddable {
final String type; final String? type;
final dynamic data; final dynamic? data;
Embeddable(this.type, this.data) Embeddable(this.type, this.data)
: assert(type != null), : assert(type != null),
assert(data != null); assert(data != null);
Map<String, dynamic> toJson() { Map<String, dynamic> toJson() {
Map<String, String> m = {type: data}; Map<String, String> m = {type!: data};
return m; return m;
} }

@ -13,11 +13,9 @@ abstract class Leaf extends Node {
Object get value => _value; Object get value => _value;
Leaf.val(Object val) Leaf.val(Object val) : _value = val;
: assert(val != null),
_value = val;
factory Leaf([Object data]) { factory Leaf([Object? data]) {
assert(data != null); assert(data != null);
if (data is Embeddable) { if (data is Embeddable) {
@ -30,14 +28,13 @@ abstract class Leaf extends Node {
@override @override
void applyStyle(Style value) { void applyStyle(Style value) {
assert( assert((value.isInline || value.isIgnored || value.isEmpty),
value != null && (value.isInline || value.isIgnored || value.isEmpty),
'Unable to apply Style to leaf: $value'); 'Unable to apply Style to leaf: $value');
super.applyStyle(value); super.applyStyle(value);
} }
@override @override
Line get parent => super.parent as Line; Line? get parent => super.parent == null ? null : super.parent as Line;
@override @override
int get length { int get length {
@ -55,11 +52,11 @@ abstract class Leaf extends Node {
} }
@override @override
insert(int index, Object data, Style style) { insert(int index, Object data, Style? style) {
assert(data != null && index >= 0 && index <= length); assert(index >= 0 && index <= length);
Leaf node = Leaf(data); Leaf node = Leaf(data);
if (index < length) { if (index < length) {
splitAt(index).insertBefore(node); splitAt(index)!.insertBefore(node);
} else { } else {
insertAfter(node); insertAfter(node);
} }
@ -67,42 +64,42 @@ abstract class Leaf extends Node {
} }
@override @override
retain(int index, int len, Style style) { retain(int index, int len, Style? style) {
if (style == null) {
return;
}
int local = math.min(this.length - index, len); int local = math.min(this.length - index, len);
int remain = len - local; int remain = len - local;
Leaf node = _isolate(index, local); Leaf? node = _isolate(index, local);
if (node != null) {
if (remain > 0) { if (remain > 0) {
assert(node.next != null); assert(node.next != null);
node.next.retain(0, remain, style); node.next!.retain(0, remain, style);
} }
node.format(style); node.format(style);
} }
}
@override @override
delete(int index, int len) { delete(int index, int len) {
assert(index < this.length); assert(index < this.length);
int local = math.min(this.length - index, len); int local = math.min(this.length - index, len);
Leaf target = _isolate(index, local); Leaf? target = _isolate(index, local);
Leaf prev = target.previous; if (target != null) {
Leaf next = target.next; Leaf? prev = (target.previous as Leaf?);
Leaf? next = (target.next as Leaf?);
target.unlink(); target.unlink();
if (next != null) {
int remain = len - local; int remain = len - local;
if (remain > 0) { if (remain > 0) {
assert(next != null);
next.delete(0, remain); next.delete(0, remain);
} }
}
if (prev != null) { if (prev != null) {
prev.adjust(); prev.adjust();
} }
} }
}
@override @override
adjust() { adjust() {
@ -112,29 +109,35 @@ abstract class Leaf extends Node {
Text node = this as Text; Text node = this as Text;
// merging it with previous node if style is the same // merging it with previous node if style is the same
Node prev = node.previous; Node? prev = node.previous;
if (!node.isFirst && prev is Text && prev.style == node.style) { if (prev != null &&
!node.isFirst &&
prev is Text &&
prev.style == node.style) {
prev._value = prev.value + node.value; prev._value = prev.value + node.value;
node.unlink(); node.unlink();
node = prev; node = prev;
} }
// merging it with next node if style is the same // merging it with next node if style is the same
Node next = node.next; Node? next = node.next;
if (!node.isLast && next is Text && next.style == node.style) { if (next != null &&
!node.isLast &&
next is Text &&
next.style == node.style) {
node._value = node.value + next.value; node._value = node.value + next.value;
next.unlink(); next.unlink();
} }
} }
Leaf cutAt(int index) { Leaf? cutAt(int index) {
assert(index >= 0 && index <= length); assert(index >= 0 && index <= length);
Leaf cut = splitAt(index); Leaf? cut = splitAt(index);
cut?.unlink(); cut?.unlink();
return cut; return cut;
} }
Leaf splitAt(int index) { Leaf? splitAt(int index) {
assert(index >= 0 && index <= length); assert(index >= 0 && index <= length);
if (index == 0) { if (index == 0) {
return this; return this;
@ -152,7 +155,7 @@ abstract class Leaf extends Node {
return split; return split;
} }
format(Style style) { format(Style? style) {
if (style != null && style.isNotEmpty) { if (style != null && style.isNotEmpty) {
applyStyle(style); applyStyle(style);
} }
@ -160,11 +163,11 @@ abstract class Leaf extends Node {
adjust(); adjust();
} }
Leaf _isolate(int index, int length) { Leaf? _isolate(int index, int length) {
assert( assert(
index >= 0 && index < this.length && (index + length <= this.length)); index >= 0 && index < this.length && (index + length <= this.length));
Leaf target = splitAt(index); Leaf? target = splitAt(index);
target.splitAt(length); target?.splitAt(length);
return target; return target;
} }
} }

@ -25,28 +25,30 @@ class Line extends Container<Leaf> {
return children.single is Embed; return children.single is Embed;
} }
Line get nextLine { Line? get nextLine {
if (!isLast) { if (!isLast) {
return next is Block ? (next as Block).first : next; return ((next is Block ? (next as Block).first : next) as Line?);
} }
if (parent is! Block) { if (parent is! Block) {
return null; return null;
} }
if (parent.isLast) { if (parent!.isLast) {
return null; return null;
} }
return parent.next is Block ? (parent.next as Block).first : parent.next; return ((parent!.next is Block
? (parent!.next as Block).first
: parent!.next) as Line?);
} }
@override @override
Delta toDelta() { Delta toDelta() {
final delta = children final delta = children
.map((child) => child.toDelta()) .map((child) => child.toDelta())
.fold(Delta(), (a, b) => a.concat(b)); .fold(Delta(), (a, b) => (a as Delta).concat(b));
var attributes = style; var attributes = style;
if (parent is Block) { if (parent is Block) {
Block block = parent; Block block = (parent as Block);
attributes = attributes.mergeAll(block.style); attributes = attributes.mergeAll(block.style);
} }
delta.insert('\n', attributes.toJson()); delta.insert('\n', attributes.toJson());
@ -64,7 +66,7 @@ class Line extends Container<Leaf> {
} }
@override @override
insert(int index, Object data, Style style) { insert(int index, Object data, Style? style) {
if (data is Embeddable) { if (data is Embeddable) {
_insert(index, data, style); _insert(index, data, style);
return; return;
@ -91,7 +93,9 @@ class Line extends Container<Leaf> {
_unwrap(); _unwrap();
} }
if (style != null) {
_format(style); _format(style);
}
// Continue with the remaining // Continue with the remaining
String remain = text.substring(lineBreak + 1); String remain = text.substring(lineBreak + 1);
@ -99,27 +103,25 @@ class Line extends Container<Leaf> {
} }
@override @override
retain(int index, int len, Style style) { retain(int index, int len, Style? style) {
if (style == null) {
return;
}
int thisLen = this.length; int thisLen = this.length;
int local = math.min(thisLen - index, len); int local = math.min(thisLen - index, len);
if (index + local == thisLen && local == 1) { if (index + local == thisLen && local == 1) {
assert(style.values.every((attr) => attr.scope == AttributeScope.BLOCK)); assert(style != null &&
_format(style); style.values.every((attr) => attr.scope == AttributeScope.BLOCK));
_format(style!);
} else { } else {
assert(style.values.every((attr) => attr.scope == AttributeScope.INLINE)); assert(style != null &&
style.values.every((attr) => attr.scope == AttributeScope.INLINE));
assert(index + local != thisLen); assert(index + local != thisLen);
super.retain(index, local, style); super.retain(index, local, style);
} }
int remain = len - local; int remain = len - local;
if (remain > 0) { if (remain > 0) {
assert(nextLine != null); nextLine!.retain(0, remain, style);
nextLine.retain(0, remain, style);
} }
} }
@ -138,37 +140,31 @@ class Line extends Container<Leaf> {
int remain = len - local; int remain = len - local;
if (remain > 0) { if (remain > 0) {
assert(nextLine != null); nextLine!.delete(0, remain);
nextLine.delete(0, remain);
} }
if (deleted && isNotEmpty) { if (deleted && isNotEmpty) {
assert(nextLine != null); nextLine!.moveChildToNewParent(this);
nextLine.moveChildToNewParent(this); moveChildToNewParent(nextLine!);
moveChildToNewParent(nextLine);
} }
if (deleted) { if (deleted) {
Node p = parent; Node p = (parent as Node);
unlink(); unlink();
p.adjust(); p.adjust();
} }
} }
void _format(Style newStyle) { void _format(Style newStyle) {
if (newStyle == null || newStyle.isEmpty) { if (newStyle.isEmpty) {
return; return;
} }
applyStyle(newStyle); applyStyle(newStyle);
Attribute blockStyle = newStyle.getBlockExceptHeader(); Attribute? blockStyle = newStyle.getBlockExceptHeader();
if (blockStyle == null) {
return;
}
if (parent is Block) { if (parent is Block) {
Attribute parentStyle = (parent as Block).style.getBlockExceptHeader(); Attribute? parentStyle = (parent as Block).style.getBlockExceptHeader();
if (blockStyle.value == null) { if (blockStyle!.value == null) {
_unwrap(); _unwrap();
} else if (blockStyle != parentStyle) { } else if (blockStyle != parentStyle) {
_unwrap(); _unwrap();
@ -177,7 +173,7 @@ class Line extends Container<Leaf> {
_wrap(block); _wrap(block);
block.adjust(); block.adjust();
} }
} else if (blockStyle.value != null) { } else if (blockStyle!.value != null) {
Block block = Block(); Block block = Block();
block.applyAttribute(blockStyle); block.applyAttribute(blockStyle);
_wrap(block); _wrap(block);
@ -196,7 +192,7 @@ class Line extends Container<Leaf> {
if (parent is! Block) { if (parent is! Block) {
throw ArgumentError('Invalid parent'); throw ArgumentError('Invalid parent');
} }
Block block = parent; Block block = (parent as Block);
assert(block.children.contains(this)); assert(block.children.contains(this));
@ -207,10 +203,10 @@ class Line extends Container<Leaf> {
unlink(); unlink();
block.insertAfter(this); block.insertAfter(this);
} else { } else {
Block before = block.clone(); Block before = (block.clone() as Block);
block.insertBefore(before); block.insertBefore(before);
Line child = block.first; Line child = (block.first as Line);
while (child != this) { while (child != this) {
child.unlink(); child.unlink();
before.add(child); before.add(child);
@ -232,19 +228,19 @@ class Line extends Container<Leaf> {
} }
ChildQuery query = queryChild(index, false); ChildQuery query = queryChild(index, false);
while (!query.node.isLast) { while (!query.node!.isLast) {
Leaf next = last; Leaf next = (last as Leaf);
next.unlink(); next.unlink();
line.addFirst(next); line.addFirst(next);
} }
Leaf child = query.node; Leaf? child = (query.node as Leaf?);
Leaf cut = child.splitAt(query.offset); Leaf? cut = child!.splitAt(query.offset!);
cut?.unlink(); cut?.unlink();
line.addFirst(cut); line.addFirst(cut!);
return line; return line;
} }
_insert(int index, Object data, Style style) { _insert(int index, Object data, Style? style) {
assert(index == 0 || (index > 0 && index < length)); assert(index == 0 || (index > 0 && index < length));
if (data is String) { if (data is String) {
@ -256,7 +252,7 @@ class Line extends Container<Leaf> {
if (isNotEmpty) { if (isNotEmpty) {
ChildQuery result = queryChild(index, true); ChildQuery result = queryChild(index, true);
result.node.insert(result.offset, data, style); result.node!.insert(result.offset!, data, style);
return; return;
} }
@ -280,7 +276,7 @@ class Line extends Container<Leaf> {
excluded.addAll(style.values); excluded.addAll(style.values);
} else { } else {
for (Attribute attr in res.values) { for (Attribute attr in res.values) {
if (!style.containsKey(attr.key)) { if (!style.containsKey(attr.key!)) {
excluded.add(attr); excluded.add(attr);
} }
} }
@ -291,11 +287,11 @@ class Line extends Container<Leaf> {
} }
ChildQuery data = queryChild(offset, true); ChildQuery data = queryChild(offset, true);
Leaf node = data.node; Leaf? node = (data.node as Leaf?);
if (node != null) { if (node != null) {
res = res.mergeAll(node.style); res = res.mergeAll(node.style);
int pos = node.length - data.offset; int pos = node.length - data.offset!;
while (!node.isLast && pos < local) { while (!node!.isLast && pos < local) {
node = node.next as Leaf; node = node.next as Leaf;
_handle(node.style); _handle(node.style);
pos += node.length; pos += node.length;
@ -304,13 +300,13 @@ class Line extends Container<Leaf> {
res = res.mergeAll(style); res = res.mergeAll(style);
if (parent is Block) { if (parent is Block) {
Block block = parent; Block block = (parent as Block);
res = res.mergeAll(block.style); res = res.mergeAll(block.style);
} }
int remain = len - local; int remain = len - local;
if (remain > 0) { if (remain > 0) {
_handle(nextLine.collectStyle(0, remain)); _handle(nextLine!.collectStyle(0, remain));
} }
return res; return res;

@ -9,7 +9,7 @@ import 'line.dart';
/* node in a document tree */ /* node in a document tree */
abstract class Node extends LinkedListEntry<Node> { abstract class Node extends LinkedListEntry<Node> {
Container parent; Container? parent;
Style _style = Style(); Style _style = Style();
Style get style => _style; Style get style => _style;
@ -19,9 +19,6 @@ abstract class Node extends LinkedListEntry<Node> {
} }
void applyStyle(Style value) { void applyStyle(Style value) {
if (value == null) {
throw ArgumentError('null value');
}
_style = _style.mergeAll(value); _style = _style.mergeAll(value);
} }
@ -29,9 +26,9 @@ abstract class Node extends LinkedListEntry<Node> {
_style = Style(); _style = Style();
} }
bool get isFirst => list.first == this; bool get isFirst => list!.first == this;
bool get isLast => list.last == this; bool get isLast => list!.last == this;
int get length; int get length;
@ -50,14 +47,14 @@ abstract class Node extends LinkedListEntry<Node> {
Node cur = this; Node cur = this;
do { do {
cur = cur.previous; cur = cur.previous!;
offset += cur.length; offset += cur.length;
} while (!cur.isFirst); } while (!cur.isFirst);
return offset; return offset;
} }
int getDocumentOffset() { int getDocumentOffset() {
final parentOffset = (parent is! Root) ? parent.getDocumentOffset() : 0; final parentOffset = (parent is! Root) ? parent!.getDocumentOffset() : 0;
return parentOffset + getOffset(); return parentOffset + getOffset();
} }
@ -99,9 +96,9 @@ abstract class Node extends LinkedListEntry<Node> {
Delta toDelta(); Delta toDelta();
insert(int index, Object data, Style style); insert(int index, Object data, Style? style);
retain(int index, int len, Style style); retain(int index, int len, Style? style);
delete(int index, int len); delete(int index, int len);

@ -10,7 +10,7 @@ class Style {
Style() : _attributes = <String, Attribute>{}; Style() : _attributes = <String, Attribute>{};
static Style fromJson(Map<String, dynamic> attributes) { static Style fromJson(Map<String, dynamic>? attributes) {
if (attributes == null) { if (attributes == null) {
return Style(); return Style();
} }
@ -22,10 +22,10 @@ class Style {
return Style.attr(result); return Style.attr(result);
} }
Map<String, dynamic> toJson() => _attributes.isEmpty Map<String, dynamic>? toJson() => _attributes.isEmpty
? null ? null
: _attributes.map<String, dynamic>((String _, Attribute attribute) => : _attributes.map<String, dynamic>((String _, Attribute attribute) =>
MapEntry<String, dynamic>(attribute.key, attribute.value)); MapEntry<String, dynamic>(attribute.key!, attribute.value));
Iterable<String> get keys => _attributes.keys; Iterable<String> get keys => _attributes.keys;
@ -46,7 +46,7 @@ class Style {
bool containsKey(String key) => _attributes.containsKey(key); bool containsKey(String key) => _attributes.containsKey(key);
Attribute getBlockExceptHeader() { Attribute? getBlockExceptHeader() {
for (Attribute val in values) { for (Attribute val in values) {
if (val.isBlockExceptHeader) { if (val.isBlockExceptHeader) {
return val; return val;
@ -60,7 +60,7 @@ class Style {
if (attribute.value == null) { if (attribute.value == null) {
merged.remove(attribute.key); merged.remove(attribute.key);
} else { } else {
merged[attribute.key] = attribute; merged[attribute.key!] = attribute;
} }
return Style.attr(merged); return Style.attr(merged);
} }
@ -81,7 +81,7 @@ class Style {
Style put(Attribute attribute) { Style put(Attribute attribute) {
Map<String, Attribute> m = Map<String, Attribute>.from(attributes); Map<String, Attribute> m = Map<String, Attribute>.from(attributes);
m[attribute.key] = attribute; m[attribute.key!] = attribute;
return Style.attr(m); return Style.attr(m);
} }

@ -46,13 +46,12 @@ class Operation {
final Object data; final Object data;
/// Rich-text attributes set by this operation, can be `null`. /// Rich-text attributes set by this operation, can be `null`.
Map<String, dynamic> get attributes => Map<String, dynamic>? get attributes =>
_attributes == null ? null : Map<String, dynamic>.from(_attributes); _attributes == null ? null : Map<String, dynamic>.from(_attributes!);
final Map<String, dynamic> _attributes; final Map<String, dynamic>? _attributes;
Operation._(this.key, this.length, this.data, Map attributes) Operation._(this.key, this.length, this.data, Map? attributes)
: assert(key != null && length != null && data != null), : assert(_validKeys.contains(key), 'Invalid operation key "$key".'),
assert(_validKeys.contains(key), 'Invalid operation key "$key".'),
assert(() { assert(() {
if (key != Operation.insertKey) return true; if (key != Operation.insertKey) return true;
return data is String ? data.length == length : length == 1; return data is String ? data.length == length : length == 1;
@ -64,7 +63,7 @@ class Operation {
/// ///
/// If `dataDecoder` parameter is not null then it is used to additionally /// If `dataDecoder` parameter is not null then it is used to additionally
/// decode the operation's data object. Only applied to insert operations. /// decode the operation's data object. Only applied to insert operations.
static Operation fromJson(Map data, {DataDecoder dataDecoder}) { static Operation fromJson(Map data, {DataDecoder? dataDecoder}) {
dataDecoder ??= _passThroughDataDecoder; dataDecoder ??= _passThroughDataDecoder;
final map = Map<String, dynamic>.from(data); final map = Map<String, dynamic>.from(data);
if (map.containsKey(Operation.insertKey)) { if (map.containsKey(Operation.insertKey)) {
@ -95,13 +94,13 @@ class Operation {
Operation._(Operation.deleteKey, length, '', null); Operation._(Operation.deleteKey, length, '', null);
/// Creates operation which inserts [text] with optional [attributes]. /// Creates operation which inserts [text] with optional [attributes].
factory Operation.insert(dynamic data, [Map<String, dynamic> attributes]) => factory Operation.insert(dynamic data, [Map<String, dynamic>? attributes]) =>
Operation._(Operation.insertKey, data is String ? data.length : 1, data, Operation._(Operation.insertKey, data is String ? data.length : 1, data,
attributes); attributes);
/// Creates operation which retains [length] of characters and optionally /// Creates operation which retains [length] of characters and optionally
/// applies attributes. /// applies attributes.
factory Operation.retain(int length, [Map<String, dynamic> attributes]) => factory Operation.retain(int length, [Map<String, dynamic>? attributes]) =>
Operation._(Operation.retainKey, length, '', attributes); Operation._(Operation.retainKey, length, '', attributes);
/// Returns value of this operation. /// Returns value of this operation.
@ -119,7 +118,7 @@ class Operation {
bool get isRetain => key == Operation.retainKey; bool get isRetain => key == Operation.retainKey;
/// Returns `true` if this operation has no attributes, e.g. is plain text. /// Returns `true` if this operation has no attributes, e.g. is plain text.
bool get isPlain => (_attributes == null || _attributes.isEmpty); bool get isPlain => (_attributes == null || _attributes!.isEmpty);
/// Returns `true` if this operation sets at least one attribute. /// Returns `true` if this operation sets at least one attribute.
bool get isNotPlain => !isPlain; bool get isNotPlain => !isPlain;
@ -144,7 +143,8 @@ class Operation {
} }
/// Returns `true` if this operation has attribute specified by [name]. /// Returns `true` if this operation has attribute specified by [name].
bool hasAttribute(String name) => isNotPlain && _attributes.containsKey(name); bool hasAttribute(String name) =>
isNotPlain && _attributes!.containsKey(name);
/// Returns `true` if [other] operation has the same attributes as this one. /// Returns `true` if [other] operation has the same attributes as this one.
bool hasSameAttributes(Operation other) { bool hasSameAttributes(Operation other) {
@ -153,9 +153,9 @@ class Operation {
@override @override
int get hashCode { int get hashCode {
if (_attributes != null && _attributes.isNotEmpty) { if (_attributes != null && _attributes!.isNotEmpty) {
final attrsHash = final attrsHash =
hashObjects(_attributes.entries.map((e) => hash2(e.key, e.value))); hashObjects(_attributes!.entries.map((e) => hash2(e.key, e.value)));
return hash3(key, value, attrsHash); return hash3(key, value, attrsHash);
} }
return hash2(key, value); return hash2(key, value);
@ -181,8 +181,8 @@ class Operation {
/// it is a "change delta". /// it is a "change delta".
class Delta { class Delta {
/// Transforms two attribute sets. /// Transforms two attribute sets.
static Map<String, dynamic> transformAttributes( static Map<String, dynamic>? transformAttributes(
Map<String, dynamic> a, Map<String, dynamic> b, bool priority) { Map<String, dynamic>? a, Map<String, dynamic>? b, bool priority) {
if (a == null) return b; if (a == null) return b;
if (b == null) return null; if (b == null) return null;
@ -197,8 +197,8 @@ class Delta {
} }
/// Composes two attribute sets. /// Composes two attribute sets.
static Map<String, dynamic> composeAttributes( static Map<String, dynamic>? composeAttributes(
Map<String, dynamic> a, Map<String, dynamic> b, Map<String, dynamic>? a, Map<String, dynamic>? b,
{bool keepNull = false}) { {bool keepNull = false}) {
a ??= const {}; a ??= const {};
b ??= const {}; b ??= const {};
@ -217,20 +217,20 @@ class Delta {
///get anti-attr result base on base ///get anti-attr result base on base
static Map<String, dynamic> invertAttributes( static Map<String, dynamic> invertAttributes(
Map<String, dynamic> attr, Map<String, dynamic> base) { Map<String, dynamic>? attr, Map<String, dynamic>? base) {
attr ??= const {}; attr ??= const {};
base ??= const {}; base ??= const {};
var baseInverted = base.keys.fold({}, (memo, key) { Map<String, dynamic> baseInverted = base.keys.fold({}, (memo, key) {
if (base[key] != attr[key] && attr.containsKey(key)) { if (base![key] != attr![key] && attr.containsKey(key)) {
memo[key] = base[key]; (memo)[key] = base[key];
} }
return memo; return memo;
}); });
var inverted = var inverted =
Map<String, dynamic>.from(attr.keys.fold(baseInverted, (memo, key) { Map<String, dynamic>.from(attr.keys.fold(baseInverted, (memo, key) {
if (base[key] != attr[key] && !base.containsKey(key)) { if (base![key] != attr![key] && !base.containsKey(key)) {
memo[key] = null; memo[key] = null;
} }
return memo; return memo;
@ -242,9 +242,7 @@ class Delta {
int _modificationCount = 0; int _modificationCount = 0;
Delta._(List<Operation> operations) Delta._(List<Operation> operations) : _operations = operations;
: assert(operations != null),
_operations = operations;
/// Creates new empty [Delta]. /// Creates new empty [Delta].
factory Delta() => Delta._(<Operation>[]); factory Delta() => Delta._(<Operation>[]);
@ -257,7 +255,7 @@ class Delta {
/// ///
/// If `dataDecoder` parameter is not null then it is used to additionally /// If `dataDecoder` parameter is not null then it is used to additionally
/// decode the operation's data object. Only applied to insert operations. /// decode the operation's data object. Only applied to insert operations.
static Delta fromJson(List data, {DataDecoder dataDecoder}) { static Delta fromJson(List data, {DataDecoder? dataDecoder}) {
return Delta._(data return Delta._(data
.map((op) => Operation.fromJson(op, dataDecoder: dataDecoder)) .map((op) => Operation.fromJson(op, dataDecoder: dataDecoder))
.toList()); .toList());
@ -304,29 +302,29 @@ class Delta {
int get hashCode => hashObjects(_operations); int get hashCode => hashObjects(_operations);
/// Retain [count] of characters from current position. /// Retain [count] of characters from current position.
void retain(int count, [Map<String, dynamic> attributes]) { void retain(int count, [Map<String, dynamic>? attributes]) {
assert(count >= 0); assert(count >= 0);
if (count == 0) return; // no-op if (count == 0) return; // no-op
push(Operation.retain(count, attributes)); push(Operation.retain(count, attributes));
} }
/// Insert [data] at current position. /// Insert [data] at current position.
void insert(dynamic data, [Map<String, dynamic> attributes]) { void insert(dynamic data, [Map<String, dynamic>? attributes]) {
assert(data != null); assert(data != null);
if (data is String && data.isEmpty) return; // no-op if (data is String && data.isEmpty) return; // no-op
push(Operation.insert(data, attributes)); push(Operation.insert(data, attributes));
} }
/// Delete [count] characters from current position. /// Delete [count] characters from current position.
void delete(int count) { void delete(int? count) {
assert(count >= 0); assert(count != null && count >= 0);
if (count == 0) return; if (count == 0) return;
push(Operation.delete(count)); push(Operation.delete(count!));
} }
void _mergeWithTail(Operation operation) { void _mergeWithTail(Operation operation) {
assert(isNotEmpty); assert(isNotEmpty);
assert(operation != null && last.key == operation.key); assert(last.key == operation.key);
assert(operation.data is String && last.data is String); assert(operation.data is String && last.data is String);
final length = operation.length + last.length; final length = operation.length + last.length;
@ -347,6 +345,7 @@ class Delta {
/// tail is replaced with `insert('abc123')` - a compound result of the two /// tail is replaced with `insert('abc123')` - a compound result of the two
/// operations. /// operations.
void push(Operation operation) { void push(Operation operation) {
//made it to here
if (operation.isEmpty) return; if (operation.isEmpty) return;
var index = _operations.length; var index = _operations.length;
@ -396,18 +395,19 @@ class Delta {
/// Returns new operation or `null` if operations from [thisIter] and /// Returns new operation or `null` if operations from [thisIter] and
/// [otherIter] nullify each other. For instance, for the pair `insert('abc')` /// [otherIter] nullify each other. For instance, for the pair `insert('abc')`
/// and `delete(3)` composition result would be empty string. /// and `delete(3)` composition result would be empty string.
Operation _composeOperation(DeltaIterator thisIter, DeltaIterator otherIter) { Operation? _composeOperation(
DeltaIterator thisIter, DeltaIterator otherIter) {
if (otherIter.isNextInsert) return otherIter.next(); if (otherIter.isNextInsert) return otherIter.next();
if (thisIter.isNextDelete) return thisIter.next(); if (thisIter.isNextDelete) return thisIter.next();
final length = math.min(thisIter.peekLength(), otherIter.peekLength()); final length = math.min(thisIter.peekLength(), otherIter.peekLength());
final thisOp = thisIter.next(length); final thisOp = thisIter.next((length as int));
final otherOp = otherIter.next(length); final otherOp = otherIter.next(length);
assert(thisOp.length == otherOp.length); assert(thisOp!.length == otherOp!.length);
if (otherOp.isRetain) { if (otherOp!.isRetain) {
final attributes = composeAttributes( final attributes = composeAttributes(
thisOp.attributes, thisOp!.attributes,
otherOp.attributes, otherOp.attributes,
keepNull: thisOp.isRetain, keepNull: thisOp.isRetain,
); );
@ -421,7 +421,7 @@ class Delta {
} else { } else {
// otherOp == delete && thisOp in [retain, insert] // otherOp == delete && thisOp in [retain, insert]
assert(otherOp.isDelete); assert(otherOp.isDelete);
if (thisOp.isRetain) return otherOp; if (thisOp!.isRetain) return otherOp;
assert(thisOp.isInsert); assert(thisOp.isInsert);
// otherOp(delete) + thisOp(insert) => null // otherOp(delete) + thisOp(insert) => null
} }
@ -448,24 +448,24 @@ class Delta {
/// [thisIter]. /// [thisIter].
/// ///
/// Returns `null` if both operations nullify each other. /// Returns `null` if both operations nullify each other.
Operation _transformOperation( Operation? _transformOperation(
DeltaIterator thisIter, DeltaIterator otherIter, bool priority) { DeltaIterator thisIter, DeltaIterator otherIter, bool priority) {
if (thisIter.isNextInsert && (priority || !otherIter.isNextInsert)) { if (thisIter.isNextInsert && (priority || !otherIter.isNextInsert)) {
return Operation.retain(thisIter.next().length); return Operation.retain(thisIter.next()!.length);
} else if (otherIter.isNextInsert) { } else if (otherIter.isNextInsert) {
return otherIter.next(); return otherIter.next();
} }
final length = math.min(thisIter.peekLength(), otherIter.peekLength()); final length = math.min(thisIter.peekLength(), otherIter.peekLength());
final thisOp = thisIter.next(length); final thisOp = thisIter.next((length as int));
final otherOp = otherIter.next(length); final otherOp = otherIter.next(length);
assert(thisOp.length == otherOp.length); assert(thisOp!.length == otherOp!.length);
// At this point only delete and retain operations are possible. // At this point only delete and retain operations are possible.
if (thisOp.isDelete) { if (thisOp!.isDelete) {
// otherOp is either delete or retain, so they nullify each other. // otherOp is either delete or retain, so they nullify each other.
return null; return null;
} else if (otherOp.isDelete) { } else if (otherOp!.isDelete) {
return otherOp; return otherOp;
} else { } else {
// Retain otherOp which is either retain or insert. // Retain otherOp which is either retain or insert.
@ -547,7 +547,7 @@ class Delta {
/// Returns slice of this delta from [start] index (inclusive) to [end] /// Returns slice of this delta from [start] index (inclusive) to [end]
/// (exclusive). /// (exclusive).
Delta slice(int start, [int end]) { Delta slice(int start, [int? end]) {
final delta = Delta(); final delta = Delta();
var index = 0; var index = 0;
var opIterator = DeltaIterator(this); var opIterator = DeltaIterator(this);
@ -557,9 +557,9 @@ class Delta {
while (index < actualEnd && opIterator.hasNext) { while (index < actualEnd && opIterator.hasNext) {
Operation op; Operation op;
if (index < start) { if (index < start) {
op = opIterator.next(start - index); op = opIterator.next(start - index)!;
} else { } else {
op = opIterator.next(actualEnd - index); op = opIterator.next((actualEnd as int) - index)!;
delta.push(op); delta.push(op);
} }
index += op.length; index += op.length;
@ -584,7 +584,7 @@ class Delta {
var offset = 0; var offset = 0;
while (iter.hasNext && offset <= index) { while (iter.hasNext && offset <= index) {
final op = iter.next(); final op = iter.next();
if (op.isDelete) { if (op!.isDelete) {
index -= math.min(op.length, index - offset); index -= math.min(op.length, index - offset);
continue; continue;
} else if (op.isInsert && (offset < index || force)) { } else if (op.isInsert && (offset < index || force)) {
@ -614,7 +614,7 @@ class DeltaIterator {
bool get isNextRetain => nextOperationKey == Operation.retainKey; bool get isNextRetain => nextOperationKey == Operation.retainKey;
String get nextOperationKey { String? get nextOperationKey {
if (_index < delta.length) { if (_index < delta.length) {
return delta.elementAt(_index).key; return delta.elementAt(_index).key;
} else { } else {
@ -639,9 +639,7 @@ class DeltaIterator {
/// ///
/// Optional [length] specifies maximum length of operation to return. Note /// Optional [length] specifies maximum length of operation to return. Note
/// that actual length of returned operation may be less than specified value. /// that actual length of returned operation may be less than specified value.
Operation next([int length = 4294967296]) { Operation? next([int length = 4294967296]) {
assert(length != null);
if (_modificationCount != delta._modificationCount) { if (_modificationCount != delta._modificationCount) {
throw ConcurrentModificationError(delta); throw ConcurrentModificationError(delta);
} }
@ -659,13 +657,14 @@ class DeltaIterator {
_offset += actualLength; _offset += actualLength;
} }
final opData = op.isInsert && op.data is String final opData = op.isInsert && op.data is String
? (op.data as String) ? (op.data as String).substring(
.substring(_currentOffset, _currentOffset + actualLength) (_currentOffset as int), _currentOffset + (actualLength as int))
: op.data; : op.data;
final opIsNotEmpty = final opIsNotEmpty =
opData is String ? opData.isNotEmpty : true; // embeds are never empty opData is String ? opData.isNotEmpty : true; // embeds are never empty
final opLength = opData is String ? opData.length : 1; final opLength = opData is String ? opData.length : 1;
final int opActualLength = opIsNotEmpty ? opLength : actualLength; final int opActualLength =
opIsNotEmpty ? opLength : (actualLength as int);
return Operation._(opKey, opActualLength, opData, opAttributes); return Operation._(opKey, opActualLength, opData, opAttributes);
} }
return Operation.retain(length); return Operation.retain(length);
@ -674,14 +673,14 @@ class DeltaIterator {
/// Skips [length] characters in source delta. /// Skips [length] characters in source delta.
/// ///
/// Returns last skipped operation, or `null` if there was nothing to skip. /// Returns last skipped operation, or `null` if there was nothing to skip.
Operation skip(int length) { Operation? skip(int length) {
var skipped = 0; var skipped = 0;
Operation op; Operation? op;
while (skipped < length && hasNext) { while (skipped < length && hasNext) {
final opLength = peekLength(); final int opLength = (peekLength() as int);
final skip = math.min(length - skipped, opLength); final int skip = math.min(length - skipped, opLength);
op = next(skip); op = next(skip);
skipped += op.length; skipped += op!.length;
} }
return op; return op;
} }

@ -7,21 +7,14 @@ abstract class DeleteRule extends Rule {
@override @override
RuleType get type => RuleType.DELETE; RuleType get type => RuleType.DELETE;
@override
validateArgs(int len, Object data, Attribute attribute) {
assert(len != null);
assert(data == null);
assert(attribute == null);
}
} }
class CatchAllDeleteRule extends DeleteRule { class CatchAllDeleteRule extends DeleteRule {
const CatchAllDeleteRule(); const CatchAllDeleteRule();
@override @override
Delta applyRule(Delta document, int index, Delta? applyRule(Delta document, int index,
{int len, Object data, Attribute attribute}) { {int? len, Object? data, Attribute? attribute}) {
return Delta() return Delta()
..retain(index) ..retain(index)
..delete(len); ..delete(len);
@ -32,25 +25,25 @@ class PreserveLineStyleOnMergeRule extends DeleteRule {
const PreserveLineStyleOnMergeRule(); const PreserveLineStyleOnMergeRule();
@override @override
Delta applyRule(Delta document, int index, Delta? applyRule(Delta document, int index,
{int len, Object data, Attribute attribute}) { {int? len, Object? data, Attribute? attribute}) {
DeltaIterator itr = DeltaIterator(document); DeltaIterator itr = DeltaIterator(document);
itr.skip(index); itr.skip(index);
Operation op = itr.next(1); Operation op = itr.next(1)!;
if (op.data != '\n') { if (op.data != '\n') {
return null; return null;
} }
bool isNotPlain = op.isNotPlain; bool isNotPlain = op.isNotPlain;
Map<String, dynamic> attrs = op.attributes; Map<String, dynamic> attrs = op.attributes!;
assert(len != null);
itr.skip(len - 1); itr.skip(len! - 1);
Delta delta = Delta() Delta delta = Delta()
..retain(index) ..retain(index)
..delete(len); ..delete(len);
while (itr.hasNext) { while (itr.hasNext) {
op = itr.next(); op = itr.next()!;
String text = op.data is String ? op.data as String : ''; String text = op.data is String ? op.data as String : '';
int lineBreak = text.indexOf('\n'); int lineBreak = text.indexOf('\n');
if (lineBreak == -1) { if (lineBreak == -1) {
@ -58,9 +51,9 @@ class PreserveLineStyleOnMergeRule extends DeleteRule {
continue; continue;
} }
Map<String, dynamic> attributes = op.attributes == null Map<String, dynamic>? attributes = op.attributes == null
? null ? null
: op.attributes.map<String, dynamic>((String key, dynamic value) => : op.attributes!.map<String, dynamic>((String key, dynamic value) =>
MapEntry<String, dynamic>(key, null)); MapEntry<String, dynamic>(key, null));
if (isNotPlain) { if (isNotPlain) {
@ -78,23 +71,24 @@ class EnsureEmbedLineRule extends DeleteRule {
const EnsureEmbedLineRule(); const EnsureEmbedLineRule();
@override @override
Delta applyRule(Delta document, int index, Delta? applyRule(Delta document, int index,
{int len, Object data, Attribute attribute}) { {int? len, Object? data, Attribute? attribute}) {
DeltaIterator itr = DeltaIterator(document); DeltaIterator itr = DeltaIterator(document);
Operation op = itr.skip(index); Operation? op = itr.skip(index);
int indexDelta = 0, lengthDelta = 0, remain = len; assert(len != null);
int indexDelta = 0, lengthDelta = 0, remain = len!;
bool embedFound = op != null && op.data is! String; bool embedFound = op != null && op.data is! String;
bool hasLineBreakBefore = bool hasLineBreakBefore =
!embedFound && (op == null || (op?.data as String).endsWith('\n')); !embedFound && (op == null || (op.data as String).endsWith('\n'));
if (embedFound) { if (embedFound) {
Operation candidate = itr.next(1); Operation candidate = itr.next(1)!;
remain--; remain--;
if (candidate.data == '\n') { if (candidate.data == '\n') {
indexDelta++; indexDelta++;
lengthDelta--; lengthDelta--;
candidate = itr.next(1); candidate = itr.next(1)!;
remain--; remain--;
if (candidate.data == '\n') { if (candidate.data == '\n') {
lengthDelta++; lengthDelta++;
@ -104,8 +98,8 @@ class EnsureEmbedLineRule extends DeleteRule {
op = itr.skip(remain); op = itr.skip(remain);
if (op != null && if (op != null &&
(op?.data is String ? op.data as String : '').endsWith('\n')) { (op.data is String ? op.data as String : '').endsWith('\n')) {
Operation candidate = itr.next(1); Operation candidate = itr.next(1)!;
if (candidate.data is! String && !hasLineBreakBefore) { if (candidate.data is! String && !hasLineBreakBefore) {
embedFound = true; embedFound = true;
lengthDelta--; lengthDelta--;

@ -7,22 +7,15 @@ abstract class FormatRule extends Rule {
@override @override
RuleType get type => RuleType.FORMAT; RuleType get type => RuleType.FORMAT;
@override
validateArgs(int len, Object data, Attribute attribute) {
assert(len != null);
assert(data == null);
assert(attribute != null);
}
} }
class ResolveLineFormatRule extends FormatRule { class ResolveLineFormatRule extends FormatRule {
const ResolveLineFormatRule(); const ResolveLineFormatRule();
@override @override
Delta applyRule(Delta document, int index, Delta? applyRule(Delta document, int index,
{int len, Object data, Attribute attribute}) { {int? len, Object? data, Attribute? attribute}) {
if (attribute.scope != AttributeScope.BLOCK) { if (attribute != null && attribute.scope != AttributeScope.BLOCK) {
return null; return null;
} }
@ -30,20 +23,21 @@ class ResolveLineFormatRule extends FormatRule {
DeltaIterator itr = DeltaIterator(document); DeltaIterator itr = DeltaIterator(document);
itr.skip(index); itr.skip(index);
Operation op; Operation op;
for (int cur = 0; cur < len && itr.hasNext; cur += op.length) { assert(len != null);
op = itr.next(len - cur); for (int cur = 0; cur < len! && itr.hasNext; cur += op.length) {
op = itr.next(len - cur)!;
if (op.data is! String || !(op.data as String).contains('\n')) { if (op.data is! String || !(op.data as String).contains('\n')) {
delta.retain(op.length); delta.retain(op.length);
continue; continue;
} }
String text = op.data; String text = (op.data as String);
Delta tmp = Delta(); Delta tmp = Delta();
int offset = 0; int offset = 0;
for (int lineBreak = text.indexOf('\n'); for (int lineBreak = text.indexOf('\n');
lineBreak >= 0; lineBreak >= 0;
lineBreak = text.indexOf('\n', offset)) { lineBreak = text.indexOf('\n', offset)) {
tmp..retain(lineBreak - offset)..retain(1, attribute.toJson()); tmp..retain(lineBreak - offset)..retain(1, attribute!.toJson());
offset = lineBreak + 1; offset = lineBreak + 1;
} }
tmp.retain(text.length - offset); tmp.retain(text.length - offset);
@ -51,14 +45,14 @@ class ResolveLineFormatRule extends FormatRule {
} }
while (itr.hasNext) { while (itr.hasNext) {
op = itr.next(); op = itr.next()!;
String text = op.data is String ? op.data as String : ''; String text = op.data is String ? op.data as String : '';
int lineBreak = text.indexOf('\n'); int lineBreak = text.indexOf('\n');
if (lineBreak < 0) { if (lineBreak < 0) {
delta..retain(op.length); delta..retain(op.length);
continue; continue;
} }
delta..retain(lineBreak)..retain(1, attribute.toJson()); delta..retain(lineBreak)..retain(1, attribute!.toJson());
break; break;
} }
return delta; return delta;
@ -69,21 +63,23 @@ class FormatLinkAtCaretPositionRule extends FormatRule {
const FormatLinkAtCaretPositionRule(); const FormatLinkAtCaretPositionRule();
@override @override
Delta applyRule(Delta document, int index, Delta? applyRule(Delta document, int index,
{int len, Object data, Attribute attribute}) { {int? len, Object? data, Attribute? attribute}) {
if (attribute.key != Attribute.link.key || len > 0) { assert(len != null);
if (attribute != null && attribute.key != Attribute.link.key || len! > 0) {
return null; return null;
} }
Delta delta = Delta(); Delta delta = Delta();
DeltaIterator itr = DeltaIterator(document); DeltaIterator itr = DeltaIterator(document);
Operation before = itr.skip(index), after = itr.next(); Operation? before = itr.skip(index), after = itr.next();
int beg = index, retain = 0; int beg = index, retain = 0;
if (before != null && before.hasAttribute(attribute.key)) { assert(attribute != null);
if (before != null && before.hasAttribute(attribute!.key!)) {
beg -= before.length; beg -= before.length;
retain = before.length; retain = before.length;
} }
if (after != null && after.hasAttribute(attribute.key)) { if (after!.hasAttribute(attribute!.key!)) {
retain += after.length; retain += after.length;
} }
if (retain == 0) { if (retain == 0) {
@ -99,9 +95,10 @@ class ResolveInlineFormatRule extends FormatRule {
const ResolveInlineFormatRule(); const ResolveInlineFormatRule();
@override @override
Delta applyRule(Delta document, int index, Delta? applyRule(Delta document, int index,
{int len, Object data, Attribute attribute}) { {int? len, Object? data, Attribute? attribute}) {
if (attribute.scope != AttributeScope.INLINE) { assert(attribute != null && len != null);
if (attribute!.scope != AttributeScope.INLINE) {
return null; return null;
} }
@ -110,8 +107,8 @@ class ResolveInlineFormatRule extends FormatRule {
itr.skip(index); itr.skip(index);
Operation op; Operation op;
for (int cur = 0; cur < len && itr.hasNext; cur += op.length) { for (int cur = 0; cur < len! && itr.hasNext; cur += op.length) {
op = itr.next(len - cur); op = itr.next(len - cur)!;
String text = op.data is String ? op.data as String : ''; String text = op.data is String ? op.data as String : '';
int lineBreak = text.indexOf('\n'); int lineBreak = text.indexOf('\n');
if (lineBreak < 0) { if (lineBreak < 0) {

@ -9,36 +9,27 @@ abstract class InsertRule extends Rule {
@override @override
RuleType get type => RuleType.INSERT; RuleType get type => RuleType.INSERT;
@override
validateArgs(int len, Object data, Attribute attribute) {
assert(len == null);
assert(data != null);
assert(attribute == null);
}
} }
class PreserveLineStyleOnSplitRule extends InsertRule { class PreserveLineStyleOnSplitRule extends InsertRule {
const PreserveLineStyleOnSplitRule(); const PreserveLineStyleOnSplitRule();
@override @override
Delta applyRule(Delta document, int index, Delta? applyRule(Delta document, int index,
{int len, Object data, Attribute attribute}) { {int? len, Object? data, Attribute? attribute}) {
if (data is! String || (data as String) != '\n') { if (data is! String || data != '\n') {
return null; return null;
} }
DeltaIterator itr = DeltaIterator(document); DeltaIterator itr = DeltaIterator(document);
Operation before = itr.skip(index); Operation? before = itr.skip(index);
if (before == null || if (before == null ||
before.data is! String || before.data is! String ||
(before.data as String).endsWith('\n')) { (before.data as String).endsWith('\n')) {
return null; return null;
} }
Operation after = itr.next(); Operation after = itr.next()!;
if (after == null || if (after.data is! String || (after.data as String).startsWith('\n')) {
after.data is! String ||
(after.data as String).startsWith('\n')) {
return null; return null;
} }
@ -50,8 +41,8 @@ class PreserveLineStyleOnSplitRule extends InsertRule {
delta..insert('\n'); delta..insert('\n');
return delta; return delta;
} }
Tuple2<Operation, int> nextNewLine = _getNextNewLine(itr); Tuple2<Operation?, int?> nextNewLine = _getNextNewLine(itr);
Map<String, dynamic> attributes = nextNewLine?.item1?.attributes; Map<String, dynamic>? attributes = nextNewLine.item1!.attributes;
return delta..insert('\n', attributes); return delta..insert('\n', attributes);
} }
@ -61,33 +52,33 @@ class PreserveBlockStyleOnInsertRule extends InsertRule {
const PreserveBlockStyleOnInsertRule(); const PreserveBlockStyleOnInsertRule();
@override @override
Delta applyRule(Delta document, int index, Delta? applyRule(Delta document, int index,
{int len, Object data, Attribute attribute}) { {int? len, Object? data, Attribute? attribute}) {
if (data is! String || !(data as String).contains('\n')) { if (data is! String || !data.contains('\n')) {
return null; return null;
} }
DeltaIterator itr = DeltaIterator(document); DeltaIterator itr = DeltaIterator(document);
itr.skip(index); itr.skip(index);
Tuple2<Operation, int> nextNewLine = _getNextNewLine(itr); Tuple2<Operation?, int?> nextNewLine = _getNextNewLine(itr);
Style lineStyle = Style lineStyle =
Style.fromJson(nextNewLine.item1?.attributes ?? <String, dynamic>{}); Style.fromJson(nextNewLine.item1?.attributes ?? <String, dynamic>{});
Attribute attribute = lineStyle.getBlockExceptHeader(); Attribute? attribute = lineStyle.getBlockExceptHeader();
if (attribute == null) { if (attribute == null) {
return null; return null;
} }
var blockStyle = <String, dynamic>{attribute.key: attribute.value}; var blockStyle = <String, dynamic>{attribute.key!: attribute.value};
Map<String, dynamic> resetStyle; Map<String, dynamic>? resetStyle;
if (lineStyle.containsKey(Attribute.header.key)) { if (lineStyle.containsKey(Attribute.header.key!)) {
resetStyle = Attribute.header.toJson(); resetStyle = Attribute.header.toJson();
} }
List<String> lines = (data as String).split('\n'); List<String> lines = data.split('\n');
Delta delta = Delta()..retain(index); Delta delta = Delta()..retain(index);
for (int i = 0; i < lines.length; i++) { for (int i = 0; i < lines.length; i++) {
String line = lines[i]; String line = lines[i];
@ -102,9 +93,9 @@ class PreserveBlockStyleOnInsertRule extends InsertRule {
} }
if (resetStyle != null) { if (resetStyle != null) {
delta.retain(nextNewLine.item2); delta.retain(nextNewLine.item2!);
delta delta
..retain((nextNewLine.item1.data as String).indexOf('\n')) ..retain((nextNewLine.item1!.data as String).indexOf('\n'))
..retain(1, resetStyle); ..retain(1, resetStyle);
} }
@ -115,7 +106,7 @@ class PreserveBlockStyleOnInsertRule extends InsertRule {
class AutoExitBlockRule extends InsertRule { class AutoExitBlockRule extends InsertRule {
const AutoExitBlockRule(); const AutoExitBlockRule();
bool _isEmptyLine(Operation before, Operation after) { bool _isEmptyLine(Operation? before, Operation after) {
if (before == null) { if (before == null) {
return true; return true;
} }
@ -126,16 +117,16 @@ class AutoExitBlockRule extends InsertRule {
} }
@override @override
Delta applyRule(Delta document, int index, Delta? applyRule(Delta document, int index,
{int len, Object data, Attribute attribute}) { {int? len, Object? data, Attribute? attribute}) {
if (data is! String || (data as String) != '\n') { if (data is! String || data != '\n') {
return null; return null;
} }
DeltaIterator itr = DeltaIterator(document); DeltaIterator itr = DeltaIterator(document);
Operation prev = itr.skip(index), cur = itr.next(); Operation? prev = itr.skip(index), cur = itr.next();
Attribute blockStyle = Attribute? blockStyle =
Style.fromJson(cur.attributes).getBlockExceptHeader(); Style.fromJson(cur!.attributes).getBlockExceptHeader();
if (cur.isPlain || blockStyle == null) { if (cur.isPlain || blockStyle == null) {
return null; return null;
} }
@ -147,10 +138,10 @@ class AutoExitBlockRule extends InsertRule {
return null; return null;
} }
Tuple2<Operation, int> nextNewLine = _getNextNewLine(itr); Tuple2<Operation?, int?> nextNewLine = _getNextNewLine(itr);
if (nextNewLine.item1 != null && if (nextNewLine.item1 != null &&
nextNewLine.item1.attributes != null && nextNewLine.item1!.attributes != null &&
Style.fromJson(nextNewLine.item1.attributes).getBlockExceptHeader() == Style.fromJson(nextNewLine.item1!.attributes).getBlockExceptHeader() ==
blockStyle) { blockStyle) {
return null; return null;
} }
@ -168,22 +159,22 @@ class ResetLineFormatOnNewLineRule extends InsertRule {
const ResetLineFormatOnNewLineRule(); const ResetLineFormatOnNewLineRule();
@override @override
Delta applyRule(Delta document, int index, Delta? applyRule(Delta document, int index,
{int len, Object data, Attribute attribute}) { {int? len, Object? data, Attribute? attribute}) {
if (data is! String || (data as String) != '\n') { if (data is! String || data != '\n') {
return null; return null;
} }
DeltaIterator itr = DeltaIterator(document); DeltaIterator itr = DeltaIterator(document);
itr.skip(index); itr.skip(index);
Operation cur = itr.next(); Operation cur = itr.next()!;
if (cur.data is! String || !(cur.data as String).startsWith('\n')) { if (cur.data is! String || !(cur.data as String).startsWith('\n')) {
return null; return null;
} }
Map<String, dynamic> resetStyle; Map<String, dynamic>? resetStyle;
if (cur.attributes != null && if (cur.attributes != null &&
cur.attributes.containsKey(Attribute.header.key)) { cur.attributes!.containsKey(Attribute.header.key)) {
resetStyle = Attribute.header.toJson(); resetStyle = Attribute.header.toJson();
} }
return Delta() return Delta()
@ -198,18 +189,18 @@ class InsertEmbedsRule extends InsertRule {
const InsertEmbedsRule(); const InsertEmbedsRule();
@override @override
Delta applyRule(Delta document, int index, Delta? applyRule(Delta document, int index,
{int len, Object data, Attribute attribute}) { {int? len, Object? data, Attribute? attribute}) {
if (data is String) { if (data is String) {
return null; return null;
} }
Delta delta = Delta()..retain(index); Delta delta = Delta()..retain(index);
DeltaIterator itr = DeltaIterator(document); DeltaIterator itr = DeltaIterator(document);
Operation prev = itr.skip(index), cur = itr.next(); Operation? prev = itr.skip(index), cur = itr.next();
String textBefore = prev?.data is String ? prev.data as String : ''; String textBefore = prev?.data is String ? prev!.data as String : '';
String textAfter = cur.data is String ? cur.data as String : ''; String textAfter = cur!.data is String ? cur.data as String : '';
final isNewlineBefore = prev == null || textBefore.endsWith('\n'); final isNewlineBefore = prev == null || textBefore.endsWith('\n');
final isNewlineAfter = textAfter.startsWith('\n'); final isNewlineAfter = textAfter.startsWith('\n');
@ -218,12 +209,12 @@ class InsertEmbedsRule extends InsertRule {
return delta..insert(data); return delta..insert(data);
} }
Map<String, dynamic> lineStyle; Map<String, dynamic>? lineStyle;
if (textAfter.contains('\n')) { if (textAfter.contains('\n')) {
lineStyle = cur.attributes; lineStyle = cur.attributes;
} else { } else {
while (itr.hasNext) { while (itr.hasNext) {
Operation op = itr.next(); Operation op = itr.next()!;
if ((op.data is String ? op.data as String : '').indexOf('\n') >= 0) { if ((op.data is String ? op.data as String : '').indexOf('\n') >= 0) {
lineStyle = op.attributes; lineStyle = op.attributes;
break; break;
@ -246,17 +237,17 @@ class ForceNewlineForInsertsAroundEmbedRule extends InsertRule {
const ForceNewlineForInsertsAroundEmbedRule(); const ForceNewlineForInsertsAroundEmbedRule();
@override @override
Delta applyRule(Delta document, int index, Delta? applyRule(Delta document, int index,
{int len, Object data, Attribute attribute}) { {int? len, Object? data, Attribute? attribute}) {
if (data is! String) { if (data is! String) {
return null; return null;
} }
String text = data as String; String text = data;
DeltaIterator itr = DeltaIterator(document); DeltaIterator itr = DeltaIterator(document);
final prev = itr.skip(index); final prev = itr.skip(index);
final cur = itr.next(); final cur = itr.next();
bool cursorBeforeEmbed = cur.data is! String; bool cursorBeforeEmbed = cur!.data is! String;
bool cursorAfterEmbed = prev != null && prev.data is! String; bool cursorAfterEmbed = prev != null && prev.data is! String;
if (!cursorBeforeEmbed && !cursorAfterEmbed) { if (!cursorBeforeEmbed && !cursorAfterEmbed) {
@ -277,14 +268,14 @@ class AutoFormatLinksRule extends InsertRule {
const AutoFormatLinksRule(); const AutoFormatLinksRule();
@override @override
Delta applyRule(Delta document, int index, Delta? applyRule(Delta document, int index,
{int len, Object data, Attribute attribute}) { {int? len, Object? data, Attribute? attribute}) {
if (data is! String || (data as String) != ' ') { if (data is! String || data != ' ') {
return null; return null;
} }
DeltaIterator itr = DeltaIterator(document); DeltaIterator itr = DeltaIterator(document);
Operation prev = itr.skip(index); Operation? prev = itr.skip(index);
if (prev == null || prev.data is! String) { if (prev == null || prev.data is! String) {
return null; return null;
} }
@ -305,7 +296,7 @@ class AutoFormatLinksRule extends InsertRule {
return Delta() return Delta()
..retain(index - cand.length) ..retain(index - cand.length)
..retain(cand.length, attributes) ..retain(cand.length, attributes)
..insert(data as String, prev.attributes); ..insert(data, prev.attributes);
} on FormatException { } on FormatException {
return null; return null;
} }
@ -316,22 +307,22 @@ class PreserveInlineStylesRule extends InsertRule {
const PreserveInlineStylesRule(); const PreserveInlineStylesRule();
@override @override
Delta applyRule(Delta document, int index, Delta? applyRule(Delta document, int index,
{int len, Object data, Attribute attribute}) { {int? len, Object? data, Attribute? attribute}) {
if (data is! String || (data as String).contains('\n')) { if (data is! String || data.contains('\n')) {
return null; return null;
} }
DeltaIterator itr = DeltaIterator(document); DeltaIterator itr = DeltaIterator(document);
Operation prev = itr.skip(index); Operation? prev = itr.skip(index);
if (prev == null || if (prev == null ||
prev.data is! String || prev.data is! String ||
(prev.data as String).contains('\n')) { (prev.data as String).contains('\n')) {
return null; return null;
} }
Map<String, dynamic> attributes = prev.attributes; Map<String, dynamic>? attributes = prev.attributes;
String text = data as String; String text = data;
if (attributes == null || !attributes.containsKey(Attribute.link.key)) { if (attributes == null || !attributes.containsKey(Attribute.link.key)) {
return Delta() return Delta()
..retain(index) ..retain(index)
@ -342,7 +333,8 @@ class PreserveInlineStylesRule extends InsertRule {
Delta delta = Delta() Delta delta = Delta()
..retain(index) ..retain(index)
..insert(text, attributes.isEmpty ? null : attributes); ..insert(text, attributes.isEmpty ? null : attributes);
Operation next = itr.next(); Operation? next = itr.next();
//DeltaIterator method next() never returns null. Yet, this looks like null is sometimes expected? Should maybe be taken out.
if (next == null) { if (next == null) {
return delta; return delta;
} }
@ -364,19 +356,19 @@ class CatchAllInsertRule extends InsertRule {
const CatchAllInsertRule(); const CatchAllInsertRule();
@override @override
Delta applyRule(Delta document, int index, Delta? applyRule(Delta document, int index,
{int len, Object data, Attribute attribute}) { {int? len, Object? data, Attribute? attribute}) {
return Delta() return Delta()
..retain(index) ..retain(index)
..insert(data); ..insert(data);
} }
} }
Tuple2<Operation, int> _getNextNewLine(DeltaIterator iterator) { Tuple2<Operation?, int?> _getNextNewLine(DeltaIterator iterator) {
Operation op; Operation? op;
for (int skipped = 0; iterator.hasNext; skipped += op.length) { for (int skipped = 0; iterator.hasNext; skipped += op.length) {
op = iterator.next(); op = iterator.next();
int lineBreak = (op.data is String ? op.data as String : '').indexOf('\n'); int lineBreak = (op!.data is String ? op.data as String : '').indexOf('\n');
if (lineBreak >= 0) { if (lineBreak >= 0) {
return Tuple2(op, skipped); return Tuple2(op, skipped);
} }

@ -11,19 +11,16 @@ enum RuleType { INSERT, DELETE, FORMAT }
abstract class Rule { abstract class Rule {
const Rule(); const Rule();
Delta apply(Delta document, int index, Delta? apply(Delta document, int index,
{int len, Object data, Attribute attribute}) { {int? len, Object? data, Attribute? attribute}) {
assert(document != null);
assert(index != null);
validateArgs(len, data, attribute);
return applyRule(document, index, return applyRule(document, index,
len: len, data: data, attribute: attribute); len: len, data: data, attribute: attribute);
} }
validateArgs(int len, Object data, Attribute attribute); // validateArgs(int len, Object data, Attribute attribute);
Delta applyRule(Delta document, int index, Delta? applyRule(Delta document, int index,
{int len, Object data, Attribute attribute}); {int? len, Object? data, Attribute? attribute});
RuleType get type; RuleType get type;
} }
@ -53,7 +50,7 @@ class Rules {
static Rules getInstance() => _instance; static Rules getInstance() => _instance;
Delta apply(RuleType ruleType, Document document, int index, Delta apply(RuleType ruleType, Document document, int index,
{int len, Object data, Attribute attribute}) { {int? len, Object? data, Attribute? attribute}) {
final delta = document.toDelta(); final delta = document.toDelta();
for (var rule in _rules) { for (var rule in _rules) {
if (rule.type != ruleType) { if (rule.type != ruleType) {
@ -63,7 +60,7 @@ class Rules {
final result = rule.apply(delta, index, final result = rule.apply(delta, index,
len: len, data: data, attribute: attribute); len: len, data: data, attribute: attribute);
if (result != null) { if (result != null) {
print("Rule $rule applied"); print("Rule $rule applied"); //made to here
return result..trim(); return result..trim();
} }
} catch (e) { } catch (e) {

@ -0,0 +1,4 @@
// ignore: camel_case_types
class platformViewRegistry {
static registerViewFactory(String viewId, dynamic cb) {}
}

@ -0,0 +1,9 @@
import 'dart:ui' as ui;
// ignore: camel_case_types
class platformViewRegistry {
static registerViewFactory(String viewId, dynamic cb) {
// ignore:undefined_prefixed_name
ui.platformViewRegistry.registerViewFactory(viewId, cb);
}
}

@ -0,0 +1,20 @@
import 'package:flutter/foundation.dart';
import 'fake_ui.dart' if (dart.library.html) 'real_ui.dart' as ui_instance;
class PlatformViewRegistryFix {
registerViewFactory(dynamic x, dynamic y) {
if (kIsWeb) {
// ignore: undefined_prefixed_name
ui_instance.platformViewRegistry.registerViewFactory(
x,
y,
);
} else {}
}
}
class UniversalUI {
PlatformViewRegistryFix platformViewRegistry = PlatformViewRegistryFix();
}
var ui = UniversalUI();

@ -75,9 +75,10 @@ int getPositionDelta(Delta user, Delta actual) {
DeltaIterator actualItr = DeltaIterator(actual); DeltaIterator actualItr = DeltaIterator(actual);
int diff = 0; int diff = 0;
while (userItr.hasNext || actualItr.hasNext) { while (userItr.hasNext || actualItr.hasNext) {
final length = math.min(userItr.peekLength(), actualItr.peekLength()); final int length =
Operation userOperation = userItr.next(length); math.min(userItr.peekLength(), actualItr.peekLength()) as int;
Operation actualOperation = actualItr.next(length); Operation userOperation = userItr.next(length)!;
Operation actualOperation = actualItr.next(length)!;
if (userOperation.length != actualOperation.length) { if (userOperation.length != actualOperation.length) {
throw ('userOp ' + throw ('userOp ' +
userOperation.length.toString() + userOperation.length.toString() +

@ -8,7 +8,7 @@ abstract class RenderContentProxyBox implements RenderBox {
TextPosition getPositionForOffset(Offset offset); TextPosition getPositionForOffset(Offset offset);
double getFullHeightForCaret(TextPosition position); double? getFullHeightForCaret(TextPosition position);
TextRange getWordBoundary(TextPosition position); TextRange getWordBoundary(TextPosition position);
@ -24,9 +24,9 @@ abstract class RenderEditableBox extends RenderBox {
TextPosition getPositionForOffset(Offset offset); TextPosition getPositionForOffset(Offset offset);
TextPosition getPositionAbove(TextPosition position); TextPosition? getPositionAbove(TextPosition position);
TextPosition getPositionBelow(TextPosition position); TextPosition? getPositionBelow(TextPosition position);
TextRange getWordBoundary(TextPosition position); TextRange getWordBoundary(TextPosition position);

@ -14,9 +14,7 @@ class QuillController extends ChangeNotifier {
TextSelection selection; TextSelection selection;
Style toggledStyle = Style(); Style toggledStyle = Style();
QuillController({@required this.document, @required this.selection}) QuillController({required this.document, required this.selection});
: assert(document != null),
assert(selection != null);
factory QuillController.basic() { factory QuillController.basic() {
return QuillController( return QuillController(
@ -75,19 +73,18 @@ class QuillController extends ChangeNotifier {
get hasRedo => document.hasRedo; get hasRedo => document.hasRedo;
replaceText(int index, int len, Object data, TextSelection textSelection) { replaceText(int index, int len, Object data, TextSelection? textSelection) {
assert(data is String || data is Embeddable); assert(data is String || data is Embeddable);
Delta delta; Delta? delta;
if (len > 0 || data is! String || (data as String).isNotEmpty) { if (len > 0 || data is! String || data.isNotEmpty) {
try { try {
delta = document.replace(index, len, data); delta = document.replace(index, len, data);
} catch (e) { } catch (e) {
print('document.replace failed: $e'); print('document.replace failed: $e');
throw e; throw e;
} }
bool shouldRetainDelta = delta != null && bool shouldRetainDelta = toggledStyle.isNotEmpty &&
toggledStyle.isNotEmpty &&
delta.isNotEmpty && delta.isNotEmpty &&
delta.length <= 2 && delta.length <= 2 &&
delta.last.isInsert; delta.last.isInsert;
@ -161,7 +158,7 @@ class QuillController extends ChangeNotifier {
notifyListeners(); notifyListeners();
} }
compose(Delta delta, TextSelection textSelection, ChangeSource source) { compose(Delta delta, TextSelection? textSelection, ChangeSource source) {
if (delta.isNotEmpty) { if (delta.isNotEmpty) {
document.compose(delta, source); document.compose(delta, source);
} }
@ -187,8 +184,6 @@ class QuillController extends ChangeNotifier {
} }
_updateSelection(TextSelection textSelection, ChangeSource source) { _updateSelection(TextSelection textSelection, ChangeSource source) {
assert(textSelection != null);
assert(source != null);
selection = textSelection; selection = textSelection;
int end = document.length - 1; int end = document.length - 1;
selection = selection.copyWith( selection = selection.copyWith(

@ -11,25 +11,22 @@ class CursorStyle {
final Color color; final Color color;
final Color backgroundColor; final Color backgroundColor;
final double width; final double width;
final double height; final double? height;
final Radius radius; final Radius? radius;
final Offset offset; final Offset? offset;
final bool opacityAnimates; final bool opacityAnimates;
final bool paintAboveText; final bool paintAboveText;
const CursorStyle({ const CursorStyle({
@required this.color, required this.color,
@required this.backgroundColor, required this.backgroundColor,
this.width = 1.0, this.width = 1.0,
this.height, this.height,
this.radius, this.radius,
this.offset, this.offset,
this.opacityAnimates = false, this.opacityAnimates = false,
this.paintAboveText = false, this.paintAboveText = false,
}) : assert(color != null), });
assert(backgroundColor != null),
assert(opacityAnimates != null),
assert(paintAboveText != null);
@override @override
bool operator ==(Object other) => bool operator ==(Object other) =>
@ -61,25 +58,22 @@ class CursorCont extends ChangeNotifier {
final ValueNotifier<bool> show; final ValueNotifier<bool> show;
final ValueNotifier<bool> _blink; final ValueNotifier<bool> _blink;
final ValueNotifier<Color> color; final ValueNotifier<Color> color;
AnimationController _blinkOpacityCont; AnimationController? _blinkOpacityCont;
Timer _cursorTimer; Timer? _cursorTimer;
bool _targetCursorVisibility = false; bool _targetCursorVisibility = false;
CursorStyle _style; CursorStyle _style;
CursorCont({ CursorCont({
@required ValueNotifier<bool> show, required ValueNotifier<bool> show,
@required CursorStyle style, required CursorStyle style,
@required TickerProvider tickerProvider, required TickerProvider tickerProvider,
}) : assert(show != null), }) : show = show,
assert(style != null),
assert(tickerProvider != null),
show = show ?? ValueNotifier<bool>(false),
_style = style, _style = style,
_blink = ValueNotifier(false), _blink = ValueNotifier(false),
color = ValueNotifier(style.color) { color = ValueNotifier(style.color) {
_blinkOpacityCont = _blinkOpacityCont =
AnimationController(vsync: tickerProvider, duration: _FADE_DURATION); AnimationController(vsync: tickerProvider, duration: _FADE_DURATION);
_blinkOpacityCont.addListener(_onColorTick); _blinkOpacityCont!.addListener(_onColorTick);
} }
ValueNotifier<bool> get cursorBlink => _blink; ValueNotifier<bool> get cursorBlink => _blink;
@ -89,7 +83,6 @@ class CursorCont extends ChangeNotifier {
CursorStyle get style => _style; CursorStyle get style => _style;
set style(CursorStyle value) { set style(CursorStyle value) {
assert(value != null);
if (_style == value) return; if (_style == value) return;
_style = value; _style = value;
notifyListeners(); notifyListeners();
@ -97,9 +90,9 @@ class CursorCont extends ChangeNotifier {
@override @override
dispose() { dispose() {
_blinkOpacityCont.removeListener(_onColorTick); _blinkOpacityCont!.removeListener(_onColorTick);
stopCursorTimer(); stopCursorTimer();
_blinkOpacityCont.dispose(); _blinkOpacityCont!.dispose();
assert(_cursorTimer == null); assert(_cursorTimer == null);
super.dispose(); super.dispose();
} }
@ -108,9 +101,9 @@ class CursorCont extends ChangeNotifier {
_targetCursorVisibility = !_targetCursorVisibility; _targetCursorVisibility = !_targetCursorVisibility;
double targetOpacity = _targetCursorVisibility ? 1.0 : 0.0; double targetOpacity = _targetCursorVisibility ? 1.0 : 0.0;
if (style.opacityAnimates) { if (style.opacityAnimates) {
_blinkOpacityCont.animateTo(targetOpacity, curve: Curves.easeOut); _blinkOpacityCont!.animateTo(targetOpacity, curve: Curves.easeOut);
} else { } else {
_blinkOpacityCont.value = targetOpacity; _blinkOpacityCont!.value = targetOpacity;
} }
} }
@ -121,7 +114,7 @@ class CursorCont extends ChangeNotifier {
void startCursorTimer() { void startCursorTimer() {
_targetCursorVisibility = true; _targetCursorVisibility = true;
_blinkOpacityCont.value = 1.0; _blinkOpacityCont!.value = 1.0;
if (style.opacityAnimates) { if (style.opacityAnimates) {
_cursorTimer = _cursorTimer =
@ -135,11 +128,11 @@ class CursorCont extends ChangeNotifier {
_cursorTimer?.cancel(); _cursorTimer?.cancel();
_cursorTimer = null; _cursorTimer = null;
_targetCursorVisibility = false; _targetCursorVisibility = false;
_blinkOpacityCont.value = 0.0; _blinkOpacityCont!.value = 0.0;
if (style.opacityAnimates) { if (style.opacityAnimates) {
_blinkOpacityCont.stop(); _blinkOpacityCont!.stop();
_blinkOpacityCont.value = 0.0; _blinkOpacityCont!.value = 0.0;
} }
} }
@ -155,8 +148,8 @@ class CursorCont extends ChangeNotifier {
} }
_onColorTick() { _onColorTick() {
color.value = _style.color.withOpacity(_blinkOpacityCont.value); color.value = _style.color.withOpacity(_blinkOpacityCont!.value);
_blink.value = show.value && _blinkOpacityCont.value > 0; _blink.value = show.value && _blinkOpacityCont!.value > 0;
} }
} }
@ -171,20 +164,18 @@ class CursorPainter {
this.devicePixelRatio); this.devicePixelRatio);
paint(Canvas canvas, Offset offset, TextPosition position) { paint(Canvas canvas, Offset offset, TextPosition position) {
assert(prototype != null);
Offset caretOffset = Offset caretOffset =
editable.getOffsetForCaret(position, prototype) + offset; editable.getOffsetForCaret(position, prototype) + offset;
Rect caretRect = prototype.shift(caretOffset); Rect caretRect = prototype.shift(caretOffset);
if (style.offset != null) { if (style.offset != null) {
caretRect = caretRect.shift(style.offset); caretRect = caretRect.shift(style.offset!);
} }
if (caretRect.left < 0.0) { if (caretRect.left < 0.0) {
caretRect = caretRect.shift(Offset(-caretRect.left, 0.0)); caretRect = caretRect.shift(Offset(-caretRect.left, 0.0));
} }
double caretHeight = editable.getFullHeightForCaret(position); double? caretHeight = editable.getFullHeightForCaret(position);
if (caretHeight != null) { if (caretHeight != null) {
switch (defaultTargetPlatform) { switch (defaultTargetPlatform) {
case TargetPlatform.android: case TargetPlatform.android:
@ -230,7 +221,7 @@ class CursorPainter {
return; return;
} }
RRect caretRRect = RRect.fromRectAndRadius(caretRect, style.radius); RRect caretRRect = RRect.fromRectAndRadius(caretRect, style.radius!);
canvas.drawRRect(caretRRect, paint); canvas.drawRRect(caretRRect, paint);
} }
} }

@ -6,25 +6,23 @@ class QuillStyles extends InheritedWidget {
final DefaultStyles data; final DefaultStyles data;
QuillStyles({ QuillStyles({
Key key, Key? key,
@required this.data, required this.data,
@required Widget child, required Widget child,
}) : assert(data != null), }) : super(key: key, child: child);
assert(child != null),
super(key: key, child: child);
@override @override
bool updateShouldNotify(QuillStyles oldWidget) { bool updateShouldNotify(QuillStyles oldWidget) {
return data != oldWidget.data; return data != oldWidget.data;
} }
static DefaultStyles getStyles(BuildContext context, bool nullOk) { static DefaultStyles? getStyles(BuildContext context, bool nullOk) {
var widget = context.dependOnInheritedWidgetOfExactType<QuillStyles>(); var widget = context.dependOnInheritedWidgetOfExactType<QuillStyles>();
if (widget == null && nullOk) { if (widget == null && nullOk) {
return null; return null;
} }
assert(widget != null); assert(widget != null);
return widget.data; return widget!.data;
} }
} }
@ -35,31 +33,31 @@ class DefaultTextBlockStyle {
final Tuple2<double, double> lineSpacing; final Tuple2<double, double> lineSpacing;
final BoxDecoration decoration; final BoxDecoration? decoration;
DefaultTextBlockStyle( DefaultTextBlockStyle(
this.style, this.verticalSpacing, this.lineSpacing, this.decoration); this.style, this.verticalSpacing, this.lineSpacing, this.decoration);
} }
class DefaultStyles { class DefaultStyles {
final DefaultTextBlockStyle h1; final DefaultTextBlockStyle? h1;
final DefaultTextBlockStyle h2; final DefaultTextBlockStyle? h2;
final DefaultTextBlockStyle h3; final DefaultTextBlockStyle? h3;
final DefaultTextBlockStyle paragraph; final DefaultTextBlockStyle? paragraph;
final TextStyle bold; final TextStyle? bold;
final TextStyle italic; final TextStyle? italic;
final TextStyle underline; final TextStyle? underline;
final TextStyle strikeThrough; final TextStyle? strikeThrough;
final TextStyle sizeSmall; // 'small' final TextStyle? sizeSmall; // 'small'
final TextStyle sizeLarge; // 'large' final TextStyle? sizeLarge; // 'large'
final TextStyle sizeHuge; // 'huge' final TextStyle? sizeHuge; // 'huge'
final TextStyle link; final TextStyle? link;
final DefaultTextBlockStyle placeHolder; final DefaultTextBlockStyle? placeHolder;
final DefaultTextBlockStyle lists; final DefaultTextBlockStyle? lists;
final DefaultTextBlockStyle quote; final DefaultTextBlockStyle? quote;
final DefaultTextBlockStyle code; final DefaultTextBlockStyle? code;
final DefaultTextBlockStyle indent; final DefaultTextBlockStyle? indent;
final DefaultTextBlockStyle align; final DefaultTextBlockStyle? align;
DefaultStyles( DefaultStyles(
{this.h1, {this.h1,
@ -109,7 +107,7 @@ class DefaultStyles {
h1: DefaultTextBlockStyle( h1: DefaultTextBlockStyle(
defaultTextStyle.style.copyWith( defaultTextStyle.style.copyWith(
fontSize: 34.0, fontSize: 34.0,
color: defaultTextStyle.style.color.withOpacity(0.70), color: defaultTextStyle.style.color!.withOpacity(0.70),
height: 1.15, height: 1.15,
fontWeight: FontWeight.w300, fontWeight: FontWeight.w300,
), ),
@ -119,7 +117,7 @@ class DefaultStyles {
h2: DefaultTextBlockStyle( h2: DefaultTextBlockStyle(
defaultTextStyle.style.copyWith( defaultTextStyle.style.copyWith(
fontSize: 24.0, fontSize: 24.0,
color: defaultTextStyle.style.color.withOpacity(0.70), color: defaultTextStyle.style.color!.withOpacity(0.70),
height: 1.15, height: 1.15,
fontWeight: FontWeight.normal, fontWeight: FontWeight.normal,
), ),
@ -129,7 +127,7 @@ class DefaultStyles {
h3: DefaultTextBlockStyle( h3: DefaultTextBlockStyle(
defaultTextStyle.style.copyWith( defaultTextStyle.style.copyWith(
fontSize: 20.0, fontSize: 20.0,
color: defaultTextStyle.style.color.withOpacity(0.70), color: defaultTextStyle.style.color!.withOpacity(0.70),
height: 1.25, height: 1.25,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
), ),
@ -158,7 +156,7 @@ class DefaultStyles {
lists: DefaultTextBlockStyle( lists: DefaultTextBlockStyle(
baseStyle, baseSpacing, Tuple2(0.0, 6.0), null), baseStyle, baseSpacing, Tuple2(0.0, 6.0), null),
quote: DefaultTextBlockStyle( quote: DefaultTextBlockStyle(
TextStyle(color: baseStyle.color.withOpacity(0.6)), TextStyle(color: baseStyle.color!.withOpacity(0.6)),
baseSpacing, baseSpacing,
Tuple2(6.0, 2.0), Tuple2(6.0, 2.0),
BoxDecoration( BoxDecoration(

@ -21,21 +21,20 @@ class EditorTextSelectionGestureDetectorBuilder {
final EditorTextSelectionGestureDetectorBuilderDelegate delegate; final EditorTextSelectionGestureDetectorBuilderDelegate delegate;
bool shouldShowSelectionToolbar = true; bool shouldShowSelectionToolbar = true;
EditorTextSelectionGestureDetectorBuilder(this.delegate) EditorTextSelectionGestureDetectorBuilder(this.delegate);
: assert(delegate != null);
EditorState getEditor() { EditorState? getEditor() {
return delegate.getEditableTextKey().currentState; return delegate.getEditableTextKey().currentState;
} }
RenderEditor getRenderEditor() { RenderEditor? getRenderEditor() {
return this.getEditor().getRenderEditor(); return this.getEditor()?.getRenderEditor();
} }
onTapDown(TapDownDetails details) { onTapDown(TapDownDetails details) {
getRenderEditor().handleTapDown(details); getRenderEditor()?.handleTapDown(details);
PointerDeviceKind kind = details.kind; PointerDeviceKind? kind = details.kind;
shouldShowSelectionToolbar = kind == null || shouldShowSelectionToolbar = kind == null ||
kind == PointerDeviceKind.touch || kind == PointerDeviceKind.touch ||
kind == PointerDeviceKind.stylus; kind == PointerDeviceKind.stylus;
@ -45,7 +44,7 @@ class EditorTextSelectionGestureDetectorBuilder {
assert(delegate.getForcePressEnabled()); assert(delegate.getForcePressEnabled());
shouldShowSelectionToolbar = true; shouldShowSelectionToolbar = true;
if (delegate.getSelectionEnabled()) { if (delegate.getSelectionEnabled()) {
getRenderEditor().selectWordsInRange( getRenderEditor()?.selectWordsInRange(
details.globalPosition, details.globalPosition,
null, null,
SelectionChangedCause.forcePress, SelectionChangedCause.forcePress,
@ -55,19 +54,19 @@ class EditorTextSelectionGestureDetectorBuilder {
onForcePressEnd(ForcePressDetails details) { onForcePressEnd(ForcePressDetails details) {
assert(delegate.getForcePressEnabled()); assert(delegate.getForcePressEnabled());
getRenderEditor().selectWordsInRange( getRenderEditor()?.selectWordsInRange(
details.globalPosition, details.globalPosition,
null, null,
SelectionChangedCause.forcePress, SelectionChangedCause.forcePress,
); );
if (shouldShowSelectionToolbar) { if (shouldShowSelectionToolbar) {
getEditor().showToolbar(); getEditor()?.showToolbar();
} }
} }
onSingleTapUp(TapUpDetails details) { onSingleTapUp(TapUpDetails details) {
if (delegate.getSelectionEnabled()) { if (delegate.getSelectionEnabled()) {
getRenderEditor().selectWordEdge(SelectionChangedCause.tap); getRenderEditor()?.selectWordEdge(SelectionChangedCause.tap);
} }
} }
@ -75,7 +74,7 @@ class EditorTextSelectionGestureDetectorBuilder {
onSingleLongTapStart(LongPressStartDetails details) { onSingleLongTapStart(LongPressStartDetails details) {
if (delegate.getSelectionEnabled()) { if (delegate.getSelectionEnabled()) {
getRenderEditor().selectPositionAt( getRenderEditor()?.selectPositionAt(
details.globalPosition, details.globalPosition,
null, null,
SelectionChangedCause.longPress, SelectionChangedCause.longPress,
@ -85,7 +84,7 @@ class EditorTextSelectionGestureDetectorBuilder {
onSingleLongTapMoveUpdate(LongPressMoveUpdateDetails details) { onSingleLongTapMoveUpdate(LongPressMoveUpdateDetails details) {
if (delegate.getSelectionEnabled()) { if (delegate.getSelectionEnabled()) {
getRenderEditor().selectPositionAt( getRenderEditor()?.selectPositionAt(
details.globalPosition, details.globalPosition,
null, null,
SelectionChangedCause.longPress, SelectionChangedCause.longPress,
@ -95,21 +94,21 @@ class EditorTextSelectionGestureDetectorBuilder {
onSingleLongTapEnd(LongPressEndDetails details) { onSingleLongTapEnd(LongPressEndDetails details) {
if (shouldShowSelectionToolbar) { if (shouldShowSelectionToolbar) {
getEditor().showToolbar(); getEditor()?.showToolbar();
} }
} }
onDoubleTapDown(TapDownDetails details) { onDoubleTapDown(TapDownDetails details) {
if (delegate.getSelectionEnabled()) { if (delegate.getSelectionEnabled()) {
getRenderEditor().selectWord(SelectionChangedCause.tap); getRenderEditor()?.selectWord(SelectionChangedCause.tap);
if (shouldShowSelectionToolbar) { if (shouldShowSelectionToolbar) {
getEditor().showToolbar(); getEditor()?.showToolbar();
} }
} }
} }
onDragSelectionStart(DragStartDetails details) { onDragSelectionStart(DragStartDetails details) {
getRenderEditor().selectPositionAt( getRenderEditor()?.selectPositionAt(
details.globalPosition, details.globalPosition,
null, null,
SelectionChangedCause.drag, SelectionChangedCause.drag,
@ -118,7 +117,7 @@ class EditorTextSelectionGestureDetectorBuilder {
onDragSelectionUpdate( onDragSelectionUpdate(
DragStartDetails startDetails, DragUpdateDetails updateDetails) { DragStartDetails startDetails, DragUpdateDetails updateDetails) {
getRenderEditor().selectPositionAt( getRenderEditor()?.selectPositionAt(
startDetails.globalPosition, startDetails.globalPosition,
updateDetails.globalPosition, updateDetails.globalPosition,
SelectionChangedCause.drag, SelectionChangedCause.drag,

@ -21,8 +21,9 @@ import 'package:flutter_quill/widgets/raw_editor.dart';
import 'package:flutter_quill/widgets/responsive_widget.dart'; import 'package:flutter_quill/widgets/responsive_widget.dart';
import 'package:flutter_quill/widgets/text_selection.dart'; import 'package:flutter_quill/widgets/text_selection.dart';
import 'package:string_validator/string_validator.dart'; import 'package:string_validator/string_validator.dart';
import 'package:universal_html/prefer_universal/html.dart' as html; import 'package:universal_html/html.dart' as html;
import 'package:universal_ui/universal_ui.dart'; //import 'package:universal_ui/universal_ui.dart';
import 'package:flutter_quill/universal_ui/universal_ui.dart';
import 'package:url_launcher/url_launcher.dart'; import 'package:url_launcher/url_launcher.dart';
import 'box.dart'; import 'box.dart';
@ -53,9 +54,9 @@ abstract class EditorState extends State<RawEditor> {
void setTextEditingValue(TextEditingValue value); void setTextEditingValue(TextEditingValue value);
RenderEditor getRenderEditor(); RenderEditor? getRenderEditor();
EditorTextSelectionOverlay getSelectionOverlay(); EditorTextSelectionOverlay? getSelectionOverlay();
bool showToolbar(); bool showToolbar();
@ -146,51 +147,44 @@ class QuillEditor extends StatefulWidget {
final bool scrollable; final bool scrollable;
final EdgeInsetsGeometry padding; final EdgeInsetsGeometry padding;
final bool autoFocus; final bool autoFocus;
final bool showCursor; final bool? showCursor;
final bool readOnly; final bool readOnly;
final String placeholder; final String? placeholder;
final bool enableInteractiveSelection; final bool? enableInteractiveSelection;
final double minHeight; final double? minHeight;
final double maxHeight; final double? maxHeight;
final DefaultStyles customStyles; final DefaultStyles? customStyles;
final bool expands; final bool expands;
final TextCapitalization textCapitalization; final TextCapitalization textCapitalization;
final Brightness keyboardAppearance; final Brightness keyboardAppearance;
final ScrollPhysics scrollPhysics; final ScrollPhysics? scrollPhysics;
final ValueChanged<String> onLaunchUrl; final ValueChanged<String>? onLaunchUrl;
final EmbedBuilder embedBuilder; final EmbedBuilder? embedBuilder;
QuillEditor( QuillEditor(
{@required this.controller, {required this.controller,
@required this.focusNode, required this.focusNode,
@required this.scrollController, required this.scrollController,
@required this.scrollable, required this.scrollable,
@required this.padding, required this.padding,
@required this.autoFocus, required this.autoFocus,
this.showCursor, this.showCursor,
@required this.readOnly, required this.readOnly,
this.placeholder, this.placeholder,
this.enableInteractiveSelection, this.enableInteractiveSelection,
this.minHeight, this.minHeight,
this.maxHeight, this.maxHeight,
this.customStyles, this.customStyles,
@required this.expands, required this.expands,
this.textCapitalization = TextCapitalization.sentences, this.textCapitalization = TextCapitalization.sentences,
this.keyboardAppearance = Brightness.light, this.keyboardAppearance = Brightness.light,
this.scrollPhysics, this.scrollPhysics,
this.onLaunchUrl, this.onLaunchUrl,
this.embedBuilder = this.embedBuilder =
kIsWeb ? _defaultEmbedBuilderWeb : _defaultEmbedBuilder}) kIsWeb ? _defaultEmbedBuilderWeb : _defaultEmbedBuilder});
: assert(controller != null),
assert(scrollController != null),
assert(scrollable != null),
assert(focusNode != null),
assert(autoFocus != null),
assert(readOnly != null),
assert(embedBuilder != null);
factory QuillEditor.basic( factory QuillEditor.basic(
{@required QuillController controller, bool readOnly}) { {required QuillController controller, required bool readOnly}) {
return QuillEditor( return QuillEditor(
controller: controller, controller: controller,
scrollController: ScrollController(), scrollController: ScrollController(),
@ -210,7 +204,7 @@ class QuillEditor extends StatefulWidget {
class _QuillEditorState extends State<QuillEditor> class _QuillEditorState extends State<QuillEditor>
implements EditorTextSelectionGestureDetectorBuilderDelegate { implements EditorTextSelectionGestureDetectorBuilderDelegate {
final GlobalKey<EditorState> _editorKey = GlobalKey<EditorState>(); final GlobalKey<EditorState> _editorKey = GlobalKey<EditorState>();
EditorTextSelectionGestureDetectorBuilder _selectionGestureDetectorBuilder; EditorTextSelectionGestureDetectorBuilder? _selectionGestureDetectorBuilder;
@override @override
void initState() { void initState() {
@ -227,10 +221,10 @@ class _QuillEditorState extends State<QuillEditor>
TextSelectionControls textSelectionControls; TextSelectionControls textSelectionControls;
bool paintCursorAboveText; bool paintCursorAboveText;
bool cursorOpacityAnimates; bool cursorOpacityAnimates;
Offset cursorOffset; Offset? cursorOffset;
Color cursorColor; Color? cursorColor;
Color selectionColor; Color selectionColor;
Radius cursorRadius; Radius? cursorRadius;
switch (theme.platform) { switch (theme.platform) {
case TargetPlatform.android: case TargetPlatform.android:
@ -262,7 +256,7 @@ class _QuillEditorState extends State<QuillEditor>
throw UnimplementedError(); throw UnimplementedError();
} }
return _selectionGestureDetectorBuilder.build( return _selectionGestureDetectorBuilder!.build(
HitTestBehavior.translucent, HitTestBehavior.translucent,
RawEditor( RawEditor(
_editorKey, _editorKey,
@ -272,7 +266,7 @@ class _QuillEditorState extends State<QuillEditor>
widget.scrollable, widget.scrollable,
widget.padding, widget.padding,
widget.readOnly, widget.readOnly,
widget.placeholder, widget.placeholder!,
widget.onLaunchUrl, widget.onLaunchUrl,
ToolbarOptions( ToolbarOptions(
copy: widget.enableInteractiveSelection ?? true, copy: widget.enableInteractiveSelection ?? true,
@ -293,17 +287,17 @@ class _QuillEditorState extends State<QuillEditor>
opacityAnimates: cursorOpacityAnimates, opacityAnimates: cursorOpacityAnimates,
), ),
widget.textCapitalization, widget.textCapitalization,
widget.maxHeight, widget.maxHeight ?? double.maxFinite,
widget.minHeight, widget.minHeight ?? 0.0,
widget.customStyles, widget.customStyles,
widget.expands, widget.expands,
widget.autoFocus, widget.autoFocus,
selectionColor, selectionColor,
textSelectionControls, textSelectionControls,
widget.keyboardAppearance, widget.keyboardAppearance,
widget.enableInteractiveSelection, widget.enableInteractiveSelection!,
widget.scrollPhysics, widget.scrollPhysics,
widget.embedBuilder), widget.embedBuilder!),
); );
} }
@ -319,11 +313,11 @@ class _QuillEditorState extends State<QuillEditor>
@override @override
bool getSelectionEnabled() { bool getSelectionEnabled() {
return widget.enableInteractiveSelection; return widget.enableInteractiveSelection!;
} }
_requestKeyboard() { _requestKeyboard() {
_editorKey.currentState.requestKeyboard(); _editorKey.currentState!.requestKeyboard();
} }
} }
@ -337,7 +331,7 @@ class _QuillEditorSelectionGestureDetectorBuilder
onForcePressStart(ForcePressDetails details) { onForcePressStart(ForcePressDetails details) {
super.onForcePressStart(details); super.onForcePressStart(details);
if (delegate.getSelectionEnabled() && shouldShowSelectionToolbar) { if (delegate.getSelectionEnabled() && shouldShowSelectionToolbar) {
getEditor().showToolbar(); getEditor()?.showToolbar();
} }
} }
@ -352,7 +346,7 @@ class _QuillEditorSelectionGestureDetectorBuilder
switch (Theme.of(_state.context).platform) { switch (Theme.of(_state.context).platform) {
case TargetPlatform.iOS: case TargetPlatform.iOS:
case TargetPlatform.macOS: case TargetPlatform.macOS:
getRenderEditor().selectPositionAt( getRenderEditor()?.selectPositionAt(
details.globalPosition, details.globalPosition,
null, null,
SelectionChangedCause.longPress, SelectionChangedCause.longPress,
@ -362,7 +356,7 @@ class _QuillEditorSelectionGestureDetectorBuilder
case TargetPlatform.fuchsia: case TargetPlatform.fuchsia:
case TargetPlatform.linux: case TargetPlatform.linux:
case TargetPlatform.windows: case TargetPlatform.windows:
getRenderEditor().selectWordsInRange( getRenderEditor()?.selectWordsInRange(
details.globalPosition - details.offsetFromOrigin, details.globalPosition - details.offsetFromOrigin,
details.globalPosition, details.globalPosition,
SelectionChangedCause.longPress, SelectionChangedCause.longPress,
@ -378,59 +372,60 @@ class _QuillEditorSelectionGestureDetectorBuilder
return false; return false;
} }
TextPosition pos = TextPosition pos =
getRenderEditor().getPositionForOffset(details.globalPosition); getRenderEditor()!.getPositionForOffset(details.globalPosition);
containerNode.ChildQuery result = containerNode.ChildQuery result =
getEditor().widget.controller.document.queryChild(pos.offset); getEditor()!.widget.controller.document.queryChild(pos.offset);
if (result.node == null) { if (result.node == null) {
return false; return false;
} }
Line line = result.node as Line; Line line = result.node as Line;
containerNode.ChildQuery segmentResult = containerNode.ChildQuery segmentResult =
line.queryChild(result.offset, false); line.queryChild(result.offset!, false);
if (segmentResult.node == null) { if (segmentResult.node == null) {
if (line.length == 1) { if (line.length == 1) {
// tapping when no text yet on this line // tapping when no text yet on this line
_flipListCheckbox(pos, line, segmentResult); _flipListCheckbox(pos, line, segmentResult);
getEditor().widget.controller.updateSelection( getEditor()?.widget.controller.updateSelection(
TextSelection.collapsed(offset: pos.offset), ChangeSource.LOCAL); TextSelection.collapsed(offset: pos.offset), ChangeSource.LOCAL);
return true; return true;
} }
return false; return false;
} }
leaf.Leaf segment = segmentResult.node as leaf.Leaf; leaf.Leaf segment = segmentResult.node as leaf.Leaf;
if (segment.style.containsKey(Attribute.link.key)) { if (segment.style.containsKey(Attribute.link.key!)) {
var launchUrl = getEditor().widget.onLaunchUrl; var launchUrl = getEditor()!.widget.onLaunchUrl;
if (launchUrl == null) { if (launchUrl == null) {
launchUrl = _launchUrl; launchUrl = _launchUrl;
} }
String link = segment.style.attributes[Attribute.link.key].value; String? link = segment.style.attributes[Attribute.link.key]!.value;
if (getEditor().widget.readOnly && link != null) { if (getEditor()!.widget.readOnly && link != null) {
link = link.trim(); link = link.trim();
if (!linkPrefixes if (!linkPrefixes
.any((linkPrefix) => link.toLowerCase().startsWith(linkPrefix))) { .any((linkPrefix) => link!.toLowerCase().startsWith(linkPrefix))) {
link = 'https://$link'; link = 'https://$link';
} }
launchUrl(link); launchUrl(link);
} }
return false; return false;
} }
if (getEditor().widget.readOnly && segment.value is BlockEmbed) { if (getEditor()!.widget.readOnly && segment.value is BlockEmbed) {
BlockEmbed blockEmbed = segment.value as BlockEmbed; BlockEmbed blockEmbed = segment.value as BlockEmbed;
if (blockEmbed.type == 'image') { if (blockEmbed.type == 'image') {
final String imageUrl = blockEmbed.data; final String imageUrl = blockEmbed.data;
Navigator.push( Navigator.push(
getEditor().context, getEditor()!.context,
MaterialPageRoute( MaterialPageRoute(
builder: (context) => ImageTapWrapper( builder: (context) => ImageTapWrapper(
imageProvider: imageUrl.startsWith('http') imageProvider: imageUrl.startsWith('http')
? NetworkImage(imageUrl) ? NetworkImage(imageUrl)
: isBase64(imageUrl) : isBase64(imageUrl)
? Image.memory(base64.decode(imageUrl)) ? (Image.memory(base64.decode(imageUrl))
as ImageProvider<Object>)
: FileImage(io.File(imageUrl)), : FileImage(io.File(imageUrl)),
), ),
), ),
); );
} } //ImageProvider<Object>?
return false; return false;
} }
if (_flipListCheckbox(pos, line, segmentResult)) { if (_flipListCheckbox(pos, line, segmentResult)) {
@ -441,25 +436,25 @@ class _QuillEditorSelectionGestureDetectorBuilder
bool _flipListCheckbox( bool _flipListCheckbox(
TextPosition pos, Line line, containerNode.ChildQuery segmentResult) { TextPosition pos, Line line, containerNode.ChildQuery segmentResult) {
if (getEditor().widget.readOnly || if (getEditor()!.widget.readOnly ||
!line.style.containsKey(Attribute.list.key) || !line.style.containsKey(Attribute.list.key!) ||
segmentResult.offset != 0) { segmentResult.offset != 0) {
return false; return false;
} }
// segmentResult.offset == 0 means tap at the beginning of the TextLine // segmentResult.offset == 0 means tap at the beginning of the TextLine
String listVal = line.style.attributes[Attribute.list.key].value; String listVal = line.style.attributes[Attribute.list.key]!.value;
if (listVal == Attribute.unchecked.value) { if (listVal == Attribute.unchecked.value) {
getEditor() getEditor()!
.widget .widget
.controller .controller
.formatText(pos.offset, 0, Attribute.checked); .formatText(pos.offset, 0, Attribute.checked);
} else if (listVal == Attribute.checked.value) { } else if (listVal == Attribute.checked.value) {
getEditor() getEditor()!
.widget .widget
.controller .controller
.formatText(pos.offset, 0, Attribute.unchecked); .formatText(pos.offset, 0, Attribute.unchecked);
} }
getEditor().widget.controller.updateSelection( getEditor()!.widget.controller.updateSelection(
TextSelection.collapsed(offset: pos.offset), ChangeSource.LOCAL); TextSelection.collapsed(offset: pos.offset), ChangeSource.LOCAL);
return true; return true;
} }
@ -470,7 +465,7 @@ class _QuillEditorSelectionGestureDetectorBuilder
@override @override
onSingleTapUp(TapUpDetails details) { onSingleTapUp(TapUpDetails details) {
getEditor().hideToolbar(); getEditor()!.hideToolbar();
bool positionSelected = _onTapping(details); bool positionSelected = _onTapping(details);
@ -482,11 +477,11 @@ class _QuillEditorSelectionGestureDetectorBuilder
case PointerDeviceKind.mouse: case PointerDeviceKind.mouse:
case PointerDeviceKind.stylus: case PointerDeviceKind.stylus:
case PointerDeviceKind.invertedStylus: case PointerDeviceKind.invertedStylus:
getRenderEditor().selectPosition(SelectionChangedCause.tap); getRenderEditor()!.selectPosition(SelectionChangedCause.tap);
break; break;
case PointerDeviceKind.touch: case PointerDeviceKind.touch:
case PointerDeviceKind.unknown: case PointerDeviceKind.unknown:
getRenderEditor().selectWordEdge(SelectionChangedCause.tap); getRenderEditor()!.selectWordEdge(SelectionChangedCause.tap);
break; break;
} }
break; break;
@ -494,7 +489,7 @@ class _QuillEditorSelectionGestureDetectorBuilder
case TargetPlatform.fuchsia: case TargetPlatform.fuchsia:
case TargetPlatform.linux: case TargetPlatform.linux:
case TargetPlatform.windows: case TargetPlatform.windows:
getRenderEditor().selectPosition(SelectionChangedCause.tap); getRenderEditor()!.selectPosition(SelectionChangedCause.tap);
break; break;
} }
} }
@ -507,7 +502,7 @@ class _QuillEditorSelectionGestureDetectorBuilder
switch (Theme.of(_state.context).platform) { switch (Theme.of(_state.context).platform) {
case TargetPlatform.iOS: case TargetPlatform.iOS:
case TargetPlatform.macOS: case TargetPlatform.macOS:
getRenderEditor().selectPositionAt( getRenderEditor()!.selectPositionAt(
details.globalPosition, details.globalPosition,
null, null,
SelectionChangedCause.longPress, SelectionChangedCause.longPress,
@ -517,7 +512,7 @@ class _QuillEditorSelectionGestureDetectorBuilder
case TargetPlatform.fuchsia: case TargetPlatform.fuchsia:
case TargetPlatform.linux: case TargetPlatform.linux:
case TargetPlatform.windows: case TargetPlatform.windows:
getRenderEditor().selectWord(SelectionChangedCause.longPress); getRenderEditor()!.selectWord(SelectionChangedCause.longPress);
Feedback.forLongPress(_state.context); Feedback.forLongPress(_state.context);
break; break;
default: default:
@ -537,7 +532,7 @@ class RenderEditor extends RenderEditableContainerBox
bool _hasFocus = false; bool _hasFocus = false;
LayerLink _startHandleLayerLink; LayerLink _startHandleLayerLink;
LayerLink _endHandleLayerLink; LayerLink _endHandleLayerLink;
TextSelectionChangedHandler onSelectionChanged; TextSelectionChangedHandler? onSelectionChanged;
final ValueNotifier<bool> _selectionStartInViewport = final ValueNotifier<bool> _selectionStartInViewport =
ValueNotifier<bool>(true); ValueNotifier<bool>(true);
@ -548,7 +543,7 @@ class RenderEditor extends RenderEditableContainerBox
final ValueNotifier<bool> _selectionEndInViewport = ValueNotifier<bool>(true); final ValueNotifier<bool> _selectionEndInViewport = ValueNotifier<bool>(true);
RenderEditor( RenderEditor(
List<RenderEditableBox> children, List<RenderEditableBox>? children,
TextDirection textDirection, TextDirection textDirection,
EdgeInsetsGeometry padding, EdgeInsetsGeometry padding,
this.document, this.document,
@ -558,11 +553,7 @@ class RenderEditor extends RenderEditableContainerBox
this._startHandleLayerLink, this._startHandleLayerLink,
this._endHandleLayerLink, this._endHandleLayerLink,
EdgeInsets floatingCursorAddedMargin) EdgeInsets floatingCursorAddedMargin)
: assert(document != null), : super(
assert(textDirection != null),
assert(_hasFocus != null),
assert(floatingCursorAddedMargin != null),
super(
children, children,
document.root, document.root,
textDirection, textDirection,
@ -570,7 +561,6 @@ class RenderEditor extends RenderEditableContainerBox
); );
setDocument(Document doc) { setDocument(Document doc) {
assert(doc != null);
if (document == doc) { if (document == doc) {
return; return;
} }
@ -579,7 +569,6 @@ class RenderEditor extends RenderEditableContainerBox
} }
setHasFocus(bool h) { setHasFocus(bool h) {
assert(h != null);
if (_hasFocus == h) { if (_hasFocus == h) {
return; return;
} }
@ -614,15 +603,13 @@ class RenderEditor extends RenderEditableContainerBox
@override @override
List<TextSelectionPoint> getEndpointsForSelection( List<TextSelectionPoint> getEndpointsForSelection(
TextSelection textSelection) { TextSelection textSelection) {
assert(constraints != null);
if (textSelection.isCollapsed) { if (textSelection.isCollapsed) {
RenderEditableBox child = childAtPosition(textSelection.extent); RenderEditableBox child = childAtPosition(textSelection.extent);
TextPosition localPosition = TextPosition( TextPosition localPosition = TextPosition(
offset: offset:
textSelection.extentOffset - child.getContainer().getOffset()); textSelection.extentOffset - child.getContainer().getOffset());
Offset localOffset = child.getOffsetForCaret(localPosition); Offset localOffset = child.getOffsetForCaret(localPosition);
BoxParentData parentData = child.parentData; BoxParentData parentData = (child.parentData as BoxParentData);
return <TextSelectionPoint>[ return <TextSelectionPoint>[
TextSelectionPoint( TextSelectionPoint(
Offset(0.0, child.preferredLineHeight(localPosition)) + Offset(0.0, child.preferredLineHeight(localPosition)) +
@ -632,7 +619,7 @@ class RenderEditor extends RenderEditableContainerBox
]; ];
} }
Node baseNode = _container.queryChild(textSelection.start, false).node; Node? baseNode = _container.queryChild(textSelection.start, false).node;
var baseChild = firstChild; var baseChild = firstChild;
while (baseChild != null) { while (baseChild != null) {
@ -643,7 +630,7 @@ class RenderEditor extends RenderEditableContainerBox
} }
assert(baseChild != null); assert(baseChild != null);
BoxParentData baseParentData = baseChild.parentData; BoxParentData baseParentData = (baseChild!.parentData as BoxParentData);
TextSelection baseSelection = TextSelection baseSelection =
localSelection(baseChild.getContainer(), textSelection, true); localSelection(baseChild.getContainer(), textSelection, true);
TextSelectionPoint basePoint = TextSelectionPoint basePoint =
@ -651,17 +638,20 @@ class RenderEditor extends RenderEditableContainerBox
basePoint = TextSelectionPoint( basePoint = TextSelectionPoint(
basePoint.point + baseParentData.offset, basePoint.direction); basePoint.point + baseParentData.offset, basePoint.direction);
Node extentNode = _container.queryChild(textSelection.end, false).node; Node? extentNode = _container.queryChild(textSelection.end, false).node;
var extentChild = baseChild; var extentChild = baseChild;
//This may not work as intended with null-safety.
// ignore: unnecessary_null_comparison
while (extentChild != null) { while (extentChild != null) {
if (extentChild.getContainer() == extentNode) { if (extentChild.getContainer() == extentNode) {
break; break;
} }
extentChild = childAfter(extentChild); extentChild = (childAfter(extentChild) as RenderEditableBox);
} }
// ignore: unnecessary_null_comparison
assert(extentChild != null); assert(extentChild != null);
BoxParentData extentParentData = extentChild.parentData; BoxParentData extentParentData = (extentChild.parentData as BoxParentData);
TextSelection extentSelection = TextSelection extentSelection =
localSelection(extentChild.getContainer(), textSelection, true); localSelection(extentChild.getContainer(), textSelection, true);
TextSelectionPoint extentPoint = TextSelectionPoint extentPoint =
@ -672,7 +662,7 @@ class RenderEditor extends RenderEditableContainerBox
return <TextSelectionPoint>[basePoint, extentPoint]; return <TextSelectionPoint>[basePoint, extentPoint];
} }
Offset _lastTapDownPosition; Offset? _lastTapDownPosition;
@override @override
handleTapDown(TapDownDetails details) { handleTapDown(TapDownDetails details) {
@ -682,11 +672,9 @@ class RenderEditor extends RenderEditableContainerBox
@override @override
selectWordsInRange( selectWordsInRange(
Offset from, Offset from,
Offset to, Offset? to,
SelectionChangedCause cause, SelectionChangedCause cause,
) { ) {
assert(cause != null);
assert(from != null);
if (onSelectionChanged == null) { if (onSelectionChanged == null) {
return; return;
} }
@ -718,18 +706,17 @@ class RenderEditor extends RenderEditableContainerBox
return; return;
} }
if (onSelectionChanged != null) { if (onSelectionChanged != null) {
onSelectionChanged(nextSelection, cause); onSelectionChanged!(nextSelection, cause);
} }
} }
@override @override
selectWordEdge(SelectionChangedCause cause) { selectWordEdge(SelectionChangedCause cause) {
assert(cause != null);
assert(_lastTapDownPosition != null); assert(_lastTapDownPosition != null);
if (onSelectionChanged == null) { if (onSelectionChanged == null) {
return; return;
} }
TextPosition position = getPositionForOffset(_lastTapDownPosition); TextPosition position = getPositionForOffset(_lastTapDownPosition!);
RenderEditableBox child = childAtPosition(position); RenderEditableBox child = childAtPosition(position);
int nodeOffset = child.getContainer().getOffset(); int nodeOffset = child.getContainer().getOffset();
TextPosition localPosition = TextPosition( TextPosition localPosition = TextPosition(
@ -759,16 +746,14 @@ class RenderEditor extends RenderEditableContainerBox
@override @override
selectPositionAt( selectPositionAt(
Offset from, Offset from,
Offset to, Offset? to,
SelectionChangedCause cause, SelectionChangedCause cause,
) { ) {
assert(cause != null);
assert(from != null);
if (onSelectionChanged == null) { if (onSelectionChanged == null) {
return; return;
} }
TextPosition fromPosition = getPositionForOffset(from); TextPosition fromPosition = getPositionForOffset(from);
TextPosition toPosition = to == null ? null : getPositionForOffset(to); TextPosition? toPosition = to == null ? null : getPositionForOffset(to);
int baseOffset = fromPosition.offset; int baseOffset = fromPosition.offset;
int extentOffset = fromPosition.offset; int extentOffset = fromPosition.offset;
@ -787,12 +772,12 @@ class RenderEditor extends RenderEditableContainerBox
@override @override
selectWord(SelectionChangedCause cause) { selectWord(SelectionChangedCause cause) {
selectWordsInRange(_lastTapDownPosition, null, cause); selectWordsInRange(_lastTapDownPosition!, null, cause);
} }
@override @override
selectPosition(SelectionChangedCause cause) { selectPosition(SelectionChangedCause cause) {
selectPositionAt(_lastTapDownPosition, null, cause); selectPositionAt(_lastTapDownPosition!, null, cause);
} }
@override @override
@ -837,7 +822,7 @@ class RenderEditor extends RenderEditableContainerBox
} }
@override @override
bool hitTestChildren(BoxHitTestResult result, {Offset position}) { bool hitTestChildren(BoxHitTestResult result, {required Offset position}) {
return defaultHitTestChildren(result, position: position); return defaultHitTestChildren(result, position: position);
} }
@ -877,9 +862,9 @@ class RenderEditor extends RenderEditableContainerBox
@override @override
TextPosition getPositionForOffset(Offset offset) { TextPosition getPositionForOffset(Offset offset) {
Offset local = globalToLocal(offset); Offset local = globalToLocal(offset);
RenderEditableBox child = childAtOffset(local); RenderEditableBox child = childAtOffset(local)!;
BoxParentData parentData = child.parentData; BoxParentData parentData = (child.parentData as BoxParentData);
Offset localOffset = local - parentData.offset; Offset localOffset = local - parentData.offset;
TextPosition localPosition = child.getPositionForOffset(localOffset); TextPosition localPosition = child.getPositionForOffset(localOffset);
return TextPosition( return TextPosition(
@ -888,7 +873,7 @@ class RenderEditor extends RenderEditableContainerBox
); );
} }
double getOffsetToRevealCursor( double? getOffsetToRevealCursor(
double viewportHeight, double scrollOffset, double offsetInViewport) { double viewportHeight, double scrollOffset, double offsetInViewport) {
List<TextSelectionPoint> endpoints = getEndpointsForSelection(selection); List<TextSelectionPoint> endpoints = getEndpointsForSelection(selection);
TextSelectionPoint endpoint = endpoints.first; TextSelectionPoint endpoint = endpoints.first;
@ -902,7 +887,7 @@ class RenderEditor extends RenderEditableContainerBox
kMargin + kMargin +
offsetInViewport; offsetInViewport;
final caretBottom = endpoint.point.dy + kMargin + offsetInViewport; final caretBottom = endpoint.point.dy + kMargin + offsetInViewport;
double dy; double? dy;
if (caretTop < scrollOffset) { if (caretTop < scrollOffset) {
dy = caretTop; dy = caretTop;
} else if (caretBottom > scrollOffset + viewportHeight) { } else if (caretBottom > scrollOffset + viewportHeight) {
@ -927,23 +912,21 @@ class RenderEditableContainerBox extends RenderBox
containerNode.Container _container; containerNode.Container _container;
TextDirection textDirection; TextDirection textDirection;
EdgeInsetsGeometry _padding; EdgeInsetsGeometry _padding;
EdgeInsets _resolvedPadding; EdgeInsets? _resolvedPadding;
RenderEditableContainerBox(List<RenderEditableBox> children, this._container, RenderEditableContainerBox(List<RenderEditableBox>? children, this._container,
this.textDirection, this._padding) this.textDirection, this._padding)
: assert(_container != null), : assert(_padding.isNonNegative) {
assert(textDirection != null), if (children != null) {
assert(_padding != null),
assert(_padding.isNonNegative) {
addAll(children); addAll(children);
} }
}
containerNode.Container getContainer() { containerNode.Container getContainer() {
return _container; return _container;
} }
setContainer(containerNode.Container c) { setContainer(containerNode.Container c) {
assert(c != null);
if (_container == c) { if (_container == c) {
return; return;
} }
@ -954,7 +937,6 @@ class RenderEditableContainerBox extends RenderBox
EdgeInsetsGeometry getPadding() => _padding; EdgeInsetsGeometry getPadding() => _padding;
setPadding(EdgeInsetsGeometry value) { setPadding(EdgeInsetsGeometry value) {
assert(value != null);
assert(value.isNonNegative); assert(value.isNonNegative);
if (_padding == value) { if (_padding == value) {
return; return;
@ -963,22 +945,22 @@ class RenderEditableContainerBox extends RenderBox
_markNeedsPaddingResolution(); _markNeedsPaddingResolution();
} }
EdgeInsets get resolvedPadding => _resolvedPadding; EdgeInsets? get resolvedPadding => _resolvedPadding;
_resolvePadding() { _resolvePadding() {
if (_resolvedPadding != null) { if (_resolvedPadding != null) {
return; return;
} }
_resolvedPadding = _padding.resolve(textDirection); _resolvedPadding = _padding.resolve(textDirection);
_resolvedPadding = _resolvedPadding.copyWith(left: _resolvedPadding.left); _resolvedPadding = _resolvedPadding!.copyWith(left: _resolvedPadding!.left);
assert(_resolvedPadding.isNonNegative); assert(_resolvedPadding!.isNonNegative);
} }
RenderEditableBox childAtPosition(TextPosition position) { RenderEditableBox childAtPosition(TextPosition position) {
assert(firstChild != null); assert(firstChild != null);
Node targetNode = _container.queryChild(position.offset, false).node; Node? targetNode = _container.queryChild(position.offset, false).node;
var targetChild = firstChild; var targetChild = firstChild;
while (targetChild != null) { while (targetChild != null) {
@ -998,19 +980,19 @@ class RenderEditableContainerBox extends RenderBox
markNeedsLayout(); markNeedsLayout();
} }
RenderEditableBox childAtOffset(Offset offset) { RenderEditableBox? childAtOffset(Offset offset) {
assert(firstChild != null); assert(firstChild != null);
_resolvePadding(); _resolvePadding();
if (offset.dy <= _resolvedPadding.top) { if (offset.dy <= _resolvedPadding!.top) {
return firstChild; return firstChild;
} }
if (offset.dy >= size.height - _resolvedPadding.bottom) { if (offset.dy >= size.height - _resolvedPadding!.bottom) {
return lastChild; return lastChild;
} }
var child = firstChild; var child = firstChild;
double dx = -offset.dx, dy = _resolvedPadding.top; double dx = -offset.dx, dy = _resolvedPadding!.top;
while (child != null) { while (child != null) {
if (child.size.contains(offset.translate(dx, -dy))) { if (child.size.contains(offset.translate(dx, -dy))) {
return child; return child;
@ -1037,20 +1019,21 @@ class RenderEditableContainerBox extends RenderBox
_resolvePadding(); _resolvePadding();
assert(_resolvedPadding != null); assert(_resolvedPadding != null);
double mainAxisExtent = _resolvedPadding.top; double mainAxisExtent = _resolvedPadding!.top;
var child = firstChild; var child = firstChild;
BoxConstraints innerConstraints = BoxConstraints innerConstraints =
BoxConstraints.tightFor(width: constraints.maxWidth) BoxConstraints.tightFor(width: constraints.maxWidth)
.deflate(_resolvedPadding); .deflate(_resolvedPadding!);
while (child != null) { while (child != null) {
child.layout(innerConstraints, parentUsesSize: true); child.layout(innerConstraints, parentUsesSize: true);
final EditableContainerParentData childParentData = child.parentData; final EditableContainerParentData childParentData =
childParentData.offset = Offset(_resolvedPadding.left, mainAxisExtent); (child.parentData as EditableContainerParentData);
childParentData.offset = Offset(_resolvedPadding!.left, mainAxisExtent);
mainAxisExtent += child.size.height; mainAxisExtent += child.size.height;
assert(child.parentData == childParentData); assert(child.parentData == childParentData);
child = childParentData.nextSibling; child = childParentData.nextSibling;
} }
mainAxisExtent += _resolvedPadding.bottom; mainAxisExtent += _resolvedPadding!.bottom;
size = constraints.constrain(Size(constraints.maxWidth, mainAxisExtent)); size = constraints.constrain(Size(constraints.maxWidth, mainAxisExtent));
assert(size.isFinite); assert(size.isFinite);
@ -1061,7 +1044,8 @@ class RenderEditableContainerBox extends RenderBox
var child = firstChild; var child = firstChild;
while (child != null) { while (child != null) {
extent = math.max(extent, childSize(child)); extent = math.max(extent, childSize(child));
EditableContainerParentData childParentData = child.parentData; EditableContainerParentData childParentData =
(child.parentData as EditableContainerParentData);
child = childParentData.nextSibling; child = childParentData.nextSibling;
} }
return extent; return extent;
@ -1072,7 +1056,8 @@ class RenderEditableContainerBox extends RenderBox
var child = firstChild; var child = firstChild;
while (child != null) { while (child != null) {
extent += childSize(child); extent += childSize(child);
EditableContainerParentData childParentData = child.parentData; EditableContainerParentData childParentData =
(child.parentData as EditableContainerParentData);
child = childParentData.nextSibling; child = childParentData.nextSibling;
} }
return extent; return extent;
@ -1083,10 +1068,10 @@ class RenderEditableContainerBox extends RenderBox
_resolvePadding(); _resolvePadding();
return _getIntrinsicCrossAxis((RenderBox child) { return _getIntrinsicCrossAxis((RenderBox child) {
double childHeight = math.max( double childHeight = math.max(
0.0, height - _resolvedPadding.top + _resolvedPadding.bottom); 0.0, height - _resolvedPadding!.top + _resolvedPadding!.bottom);
return child.getMinIntrinsicWidth(childHeight) + return child.getMinIntrinsicWidth(childHeight) +
_resolvedPadding.left + _resolvedPadding!.left +
_resolvedPadding.right; _resolvedPadding!.right;
}); });
} }
@ -1095,10 +1080,10 @@ class RenderEditableContainerBox extends RenderBox
_resolvePadding(); _resolvePadding();
return _getIntrinsicCrossAxis((RenderBox child) { return _getIntrinsicCrossAxis((RenderBox child) {
double childHeight = math.max( double childHeight = math.max(
0.0, height - _resolvedPadding.top + _resolvedPadding.bottom); 0.0, height - _resolvedPadding!.top + _resolvedPadding!.bottom);
return child.getMaxIntrinsicWidth(childHeight) + return child.getMaxIntrinsicWidth(childHeight) +
_resolvedPadding.left + _resolvedPadding!.left +
_resolvedPadding.right; _resolvedPadding!.right;
}); });
} }
@ -1106,11 +1091,11 @@ class RenderEditableContainerBox extends RenderBox
double computeMinIntrinsicHeight(double width) { double computeMinIntrinsicHeight(double width) {
_resolvePadding(); _resolvePadding();
return _getIntrinsicMainAxis((RenderBox child) { return _getIntrinsicMainAxis((RenderBox child) {
double childWidth = double childWidth = math.max(
math.max(0.0, width - _resolvedPadding.left + _resolvedPadding.right); 0.0, width - _resolvedPadding!.left + _resolvedPadding!.right);
return child.getMinIntrinsicHeight(childWidth) + return child.getMinIntrinsicHeight(childWidth) +
_resolvedPadding.top + _resolvedPadding!.top +
_resolvedPadding.bottom; _resolvedPadding!.bottom;
}); });
} }
@ -1118,18 +1103,18 @@ class RenderEditableContainerBox extends RenderBox
double computeMaxIntrinsicHeight(double width) { double computeMaxIntrinsicHeight(double width) {
_resolvePadding(); _resolvePadding();
return _getIntrinsicMainAxis((RenderBox child) { return _getIntrinsicMainAxis((RenderBox child) {
final childWidth = final childWidth = math.max(
math.max(0.0, width - _resolvedPadding.left + _resolvedPadding.right); 0.0, width - _resolvedPadding!.left + _resolvedPadding!.right);
return child.getMaxIntrinsicHeight(childWidth) + return child.getMaxIntrinsicHeight(childWidth) +
_resolvedPadding.top + _resolvedPadding!.top +
_resolvedPadding.bottom; _resolvedPadding!.bottom;
}); });
} }
@override @override
double computeDistanceToActualBaseline(TextBaseline baseline) { double computeDistanceToActualBaseline(TextBaseline baseline) {
_resolvePadding(); _resolvePadding();
return defaultComputeDistanceToFirstActualBaseline(baseline) + return defaultComputeDistanceToFirstActualBaseline(baseline)! +
_resolvedPadding.top; _resolvedPadding!.top;
} }
} }

@ -8,7 +8,7 @@ class ImageTapWrapper extends StatelessWidget {
this.imageProvider, this.imageProvider,
}); });
final ImageProvider imageProvider; final ImageProvider? imageProvider;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {

@ -58,10 +58,7 @@ class KeyboardListener {
LogicalKeyboardKey.keyA: InputShortcut.SELECT_ALL, LogicalKeyboardKey.keyA: InputShortcut.SELECT_ALL,
}; };
KeyboardListener(this.onCursorMove, this.onShortcut, this.onDelete) KeyboardListener(this.onCursorMove, this.onShortcut, this.onDelete);
: assert(onCursorMove != null),
assert(onShortcut != null),
assert(onDelete != null);
bool handleRawKeyEvent(RawKeyEvent event) { bool handleRawKeyEvent(RawKeyEvent event) {
if (event is! RawKeyDownEvent) { if (event is! RawKeyDownEvent) {
@ -90,7 +87,7 @@ class KeyboardListener {
} else if (isMacOS } else if (isMacOS
? event.isMetaPressed ? event.isMetaPressed
: event.isControlPressed && _shortcutKeys.contains(key)) { : event.isControlPressed && _shortcutKeys.contains(key)) {
onShortcut(_keyToShortcut[key]); onShortcut(_keyToShortcut[key]!);
} else if (key == LogicalKeyboardKey.delete) { } else if (key == LogicalKeyboardKey.delete) {
onDelete(true); onDelete(true);
} else if (key == LogicalKeyboardKey.backspace) { } else if (key == LogicalKeyboardKey.backspace) {

@ -7,8 +7,12 @@ class BaselineProxy extends SingleChildRenderObjectWidget {
final TextStyle textStyle; final TextStyle textStyle;
final EdgeInsets padding; final EdgeInsets padding;
BaselineProxy({Key key, Widget child, this.textStyle, this.padding}) BaselineProxy({
: super(key: key, child: child); Key? key,
Widget? child,
required this.textStyle,
required this.padding,
}) : super(key: key, child: child);
@override @override
RenderBaselineProxy createRenderObject(BuildContext context) { RenderBaselineProxy createRenderObject(BuildContext context) {
@ -30,9 +34,9 @@ class BaselineProxy extends SingleChildRenderObjectWidget {
class RenderBaselineProxy extends RenderProxyBox { class RenderBaselineProxy extends RenderProxyBox {
RenderBaselineProxy( RenderBaselineProxy(
RenderParagraph child, RenderParagraph? child,
TextStyle textStyle, TextStyle textStyle,
EdgeInsets padding, EdgeInsets? padding,
) : _prototypePainter = TextPainter( ) : _prototypePainter = TextPainter(
text: TextSpan(text: ' ', style: textStyle), text: TextSpan(text: ' ', style: textStyle),
textDirection: TextDirection.ltr, textDirection: TextDirection.ltr,
@ -43,18 +47,16 @@ class RenderBaselineProxy extends RenderProxyBox {
final TextPainter _prototypePainter; final TextPainter _prototypePainter;
set textStyle(TextStyle value) { set textStyle(TextStyle value) {
assert(value != null); if (_prototypePainter.text!.style == value) {
if (_prototypePainter.text.style == value) {
return; return;
} }
_prototypePainter.text = TextSpan(text: ' ', style: value); _prototypePainter.text = TextSpan(text: ' ', style: value);
markNeedsLayout(); markNeedsLayout();
} }
EdgeInsets _padding; EdgeInsets? _padding;
set padding(EdgeInsets value) { set padding(EdgeInsets value) {
assert(value != null);
if (_padding == value) { if (_padding == value) {
return; return;
} }
@ -65,8 +67,7 @@ class RenderBaselineProxy extends RenderProxyBox {
@override @override
double computeDistanceToActualBaseline(TextBaseline baseline) => double computeDistanceToActualBaseline(TextBaseline baseline) =>
_prototypePainter.computeDistanceToActualBaseline(baseline) + _prototypePainter.computeDistanceToActualBaseline(baseline) +
_padding?.top ?? (_padding == null ? 0.0 : _padding!.top);
0.0;
@override @override
performLayout() { performLayout() {
@ -84,7 +85,7 @@ class EmbedProxy extends SingleChildRenderObjectWidget {
} }
class RenderEmbedProxy extends RenderProxyBox implements RenderContentProxyBox { class RenderEmbedProxy extends RenderProxyBox implements RenderContentProxyBox {
RenderEmbedProxy(RenderBox child) : super(child); RenderEmbedProxy(RenderBox? child) : super(child);
@override @override
List<TextBox> getBoxesForSelection(TextSelection selection) { List<TextBox> getBoxesForSelection(TextSelection selection) {
@ -106,9 +107,7 @@ class RenderEmbedProxy extends RenderProxyBox implements RenderContentProxyBox {
@override @override
Offset getOffsetForCaret(TextPosition position, Rect caretPrototype) { Offset getOffsetForCaret(TextPosition position, Rect caretPrototype) {
assert(position.offset != null && assert(position.offset <= 1 && position.offset >= 0);
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.0);
} }
@ -134,7 +133,7 @@ class RichTextProxy extends SingleChildRenderObjectWidget {
final Locale locale; final Locale locale;
final StrutStyle strutStyle; final StrutStyle strutStyle;
final TextWidthBasis textWidthBasis; final TextWidthBasis textWidthBasis;
final TextHeightBehavior textHeightBehavior; final TextHeightBehavior? textHeightBehavior;
@override @override
RenderParagraphProxy createRenderObject(BuildContext context) { RenderParagraphProxy createRenderObject(BuildContext context) {
@ -160,17 +159,13 @@ class RichTextProxy extends SingleChildRenderObjectWidget {
this.strutStyle, this.strutStyle,
this.textWidthBasis, this.textWidthBasis,
this.textHeightBehavior) this.textHeightBehavior)
: assert(child != null), : super(child: child);
assert(textStyle != null),
assert(textAlign != null),
assert(textDirection != null),
assert(locale != null),
assert(strutStyle != null),
super(child: child);
@override @override
void updateRenderObject( void updateRenderObject(
BuildContext context, covariant RenderParagraphProxy renderObject) { BuildContext context,
covariant RenderParagraphProxy renderObject,
) {
renderObject.textStyle = textStyle; renderObject.textStyle = textStyle;
renderObject.textAlign = textAlign; renderObject.textAlign = textAlign;
renderObject.textDirection = textDirection; renderObject.textDirection = textDirection;
@ -178,14 +173,16 @@ class RichTextProxy extends SingleChildRenderObjectWidget {
renderObject.locale = locale; renderObject.locale = locale;
renderObject.strutStyle = strutStyle; renderObject.strutStyle = strutStyle;
renderObject.textWidthBasis = textWidthBasis; renderObject.textWidthBasis = textWidthBasis;
renderObject.textHeightBehavior = textHeightBehavior; if (textHeightBehavior != null) {
renderObject.textHeightBehavior = textHeightBehavior!;
}
} }
} }
class RenderParagraphProxy extends RenderProxyBox class RenderParagraphProxy extends RenderProxyBox
implements RenderContentProxyBox { implements RenderContentProxyBox {
RenderParagraphProxy( RenderParagraphProxy(
RenderParagraph child, RenderParagraph? child,
TextStyle textStyle, TextStyle textStyle,
TextAlign textAlign, TextAlign textAlign,
TextDirection textDirection, TextDirection textDirection,
@ -193,7 +190,7 @@ class RenderParagraphProxy extends RenderProxyBox
StrutStyle strutStyle, StrutStyle strutStyle,
Locale locale, Locale locale,
TextWidthBasis textWidthBasis, TextWidthBasis textWidthBasis,
TextHeightBehavior textHeightBehavior, TextHeightBehavior? textHeightBehavior,
) : _prototypePainter = TextPainter( ) : _prototypePainter = TextPainter(
text: TextSpan(text: ' ', style: textStyle), text: TextSpan(text: ' ', style: textStyle),
textAlign: textAlign, textAlign: textAlign,
@ -208,8 +205,7 @@ class RenderParagraphProxy extends RenderProxyBox
final TextPainter _prototypePainter; final TextPainter _prototypePainter;
set textStyle(TextStyle value) { set textStyle(TextStyle value) {
assert(value != null); if (_prototypePainter.text!.style == value) {
if (_prototypePainter.text.style == value) {
return; return;
} }
_prototypePainter.text = TextSpan(text: ' ', style: value); _prototypePainter.text = TextSpan(text: ' ', style: value);
@ -217,7 +213,6 @@ class RenderParagraphProxy extends RenderProxyBox
} }
set textAlign(TextAlign value) { set textAlign(TextAlign value) {
assert(value != null);
if (_prototypePainter.textAlign == value) { if (_prototypePainter.textAlign == value) {
return; return;
} }
@ -226,7 +221,6 @@ class RenderParagraphProxy extends RenderProxyBox
} }
set textDirection(TextDirection value) { set textDirection(TextDirection value) {
assert(value != null);
if (_prototypePainter.textDirection == value) { if (_prototypePainter.textDirection == value) {
return; return;
} }
@ -235,7 +229,6 @@ class RenderParagraphProxy extends RenderProxyBox
} }
set textScaleFactor(double value) { set textScaleFactor(double value) {
assert(value != null);
if (_prototypePainter.textScaleFactor == value) { if (_prototypePainter.textScaleFactor == value) {
return; return;
} }
@ -244,7 +237,6 @@ class RenderParagraphProxy extends RenderProxyBox
} }
set strutStyle(StrutStyle value) { set strutStyle(StrutStyle value) {
assert(value != null);
if (_prototypePainter.strutStyle == value) { if (_prototypePainter.strutStyle == value) {
return; return;
} }
@ -261,7 +253,6 @@ class RenderParagraphProxy extends RenderProxyBox
} }
set textWidthBasis(TextWidthBasis value) { set textWidthBasis(TextWidthBasis value) {
assert(value != null);
if (_prototypePainter.textWidthBasis == value) { if (_prototypePainter.textWidthBasis == value) {
return; return;
} }
@ -278,7 +269,7 @@ class RenderParagraphProxy extends RenderProxyBox
} }
@override @override
RenderParagraph get child => super.child; RenderParagraph? get child => super.child as RenderParagraph?;
@override @override
double getPreferredLineHeight() { double getPreferredLineHeight() {
@ -287,23 +278,23 @@ class RenderParagraphProxy extends RenderProxyBox
@override @override
Offset getOffsetForCaret(TextPosition position, Rect caretPrototype) => Offset getOffsetForCaret(TextPosition position, Rect caretPrototype) =>
child.getOffsetForCaret(position, caretPrototype); child!.getOffsetForCaret(position, caretPrototype);
@override @override
TextPosition getPositionForOffset(Offset offset) => TextPosition getPositionForOffset(Offset offset) =>
child.getPositionForOffset(offset); child!.getPositionForOffset(offset);
@override @override
double getFullHeightForCaret(TextPosition position) => double? getFullHeightForCaret(TextPosition position) =>
child.getFullHeightForCaret(position); child!.getFullHeightForCaret(position);
@override @override
TextRange getWordBoundary(TextPosition position) => TextRange getWordBoundary(TextPosition position) =>
child.getWordBoundary(position); child!.getWordBoundary(position);
@override @override
List<TextBox> getBoxesForSelection(TextSelection selection) => List<TextBox> getBoxesForSelection(TextSelection selection) =>
child.getBoxesForSelection(selection); child!.getBoxesForSelection(selection);
@override @override
performLayout() { performLayout() {

@ -32,12 +32,12 @@ import 'keyboard_listener.dart';
class RawEditor extends StatefulWidget { class RawEditor extends StatefulWidget {
final QuillController controller; final QuillController controller;
final FocusNode focusNode; final FocusNode focusNode;
final ScrollController scrollController; final ScrollController? scrollController;
final bool scrollable; final bool scrollable;
final EdgeInsetsGeometry padding; final EdgeInsetsGeometry padding;
final bool readOnly; final bool readOnly;
final String placeholder; final String placeholder;
final ValueChanged<String> onLaunchUrl; final ValueChanged<String>? onLaunchUrl;
final ToolbarOptions toolbarOptions; final ToolbarOptions toolbarOptions;
final bool showSelectionHandles; final bool showSelectionHandles;
final bool showCursor; final bool showCursor;
@ -45,14 +45,14 @@ class RawEditor extends StatefulWidget {
final TextCapitalization textCapitalization; final TextCapitalization textCapitalization;
final double maxHeight; final double maxHeight;
final double minHeight; final double minHeight;
final DefaultStyles customStyles; final DefaultStyles? customStyles;
final bool expands; final bool expands;
final bool autoFocus; final bool autoFocus;
final Color selectionColor; final Color selectionColor;
final TextSelectionControls selectionCtrls; final TextSelectionControls? selectionCtrls;
final Brightness keyboardAppearance; final Brightness keyboardAppearance;
final bool enableInteractiveSelection; final bool enableInteractiveSelection;
final ScrollPhysics scrollPhysics; final ScrollPhysics? scrollPhysics;
final EmbedBuilder embedBuilder; final EmbedBuilder embedBuilder;
RawEditor( RawEditor(
@ -67,7 +67,7 @@ class RawEditor extends StatefulWidget {
this.onLaunchUrl, this.onLaunchUrl,
this.toolbarOptions, this.toolbarOptions,
this.showSelectionHandles, this.showSelectionHandles,
bool showCursor, bool? showCursor,
this.cursorStyle, this.cursorStyle,
this.textCapitalization, this.textCapitalization,
this.maxHeight, this.maxHeight,
@ -81,26 +81,10 @@ class RawEditor extends StatefulWidget {
this.enableInteractiveSelection, this.enableInteractiveSelection,
this.scrollPhysics, this.scrollPhysics,
this.embedBuilder) this.embedBuilder)
: assert(controller != null, 'controller cannot be null'), : assert(maxHeight > 0, 'maxHeight cannot be null'),
assert(focusNode != null, 'focusNode cannot be null'), assert(minHeight >= 0, 'minHeight cannot be null'),
assert(scrollable || scrollController != null, assert(maxHeight >= minHeight, 'maxHeight cannot be null'),
'scrollController cannot be null'),
assert(selectionColor != null, 'selectionColor cannot be null'),
assert(enableInteractiveSelection != null,
'enableInteractiveSelection cannot be null'),
assert(showSelectionHandles != null,
'showSelectionHandles cannot be null'),
assert(readOnly != null, 'readOnly cannot be null'),
assert(maxHeight == null || maxHeight > 0, 'maxHeight cannot be null'),
assert(minHeight == null || minHeight >= 0, 'minHeight cannot be null'),
assert(maxHeight == null || minHeight == null || maxHeight >= minHeight,
'maxHeight cannot be null'),
assert(autoFocus != null, 'autoFocus cannot be null'),
assert(toolbarOptions != null, 'toolbarOptions cannot be null'),
showCursor = showCursor ?? !readOnly, showCursor = showCursor ?? !readOnly,
assert(embedBuilder != null, 'embedBuilder cannot be null'),
assert(expands != null, 'expands cannot be null'),
assert(padding != null),
super(key: key); super(key: key);
@override @override
@ -117,20 +101,20 @@ class RawEditorState extends EditorState
implements TextSelectionDelegate, TextInputClient { implements TextSelectionDelegate, TextInputClient {
final GlobalKey _editorKey = GlobalKey(); final GlobalKey _editorKey = GlobalKey();
final List<TextEditingValue> _sentRemoteValues = []; final List<TextEditingValue> _sentRemoteValues = [];
TextInputConnection _textInputConnection; TextInputConnection? _textInputConnection;
TextEditingValue _lastKnownRemoteTextEditingValue; TextEditingValue? _lastKnownRemoteTextEditingValue;
int _cursorResetLocation = -1; int _cursorResetLocation = -1;
bool _wasSelectingVerticallyWithKeyboard = false; bool _wasSelectingVerticallyWithKeyboard = false;
EditorTextSelectionOverlay _selectionOverlay; EditorTextSelectionOverlay? _selectionOverlay;
FocusAttachment _focusAttachment; FocusAttachment? _focusAttachment;
CursorCont _cursorCont; CursorCont? _cursorCont;
ScrollController _scrollController; ScrollController? _scrollController;
KeyboardVisibilityController _keyboardVisibilityController; KeyboardVisibilityController? _keyboardVisibilityController;
StreamSubscription<bool> _keyboardVisibilitySubscription; StreamSubscription<bool>? _keyboardVisibilitySubscription;
KeyboardListener _keyboardListener; KeyboardListener? _keyboardListener;
bool _didAutoFocus = false; bool _didAutoFocus = false;
bool _keyboardVisible = false; bool _keyboardVisible = false;
DefaultStyles _styles; DefaultStyles? _styles;
final ClipboardStatusNotifier _clipboardStatus = ClipboardStatusNotifier(); final ClipboardStatusNotifier _clipboardStatus = ClipboardStatusNotifier();
final LayerLink _toolbarLayerLink = LayerLink(); final LayerLink _toolbarLayerLink = LayerLink();
final LayerLink _startHandleLayerLink = LayerLink(); final LayerLink _startHandleLayerLink = LayerLink();
@ -140,7 +124,6 @@ class RawEditorState extends EditorState
TextDirection get _textDirection { TextDirection get _textDirection {
TextDirection result = Directionality.of(context); TextDirection result = Directionality.of(context);
assert(result != null);
return result; return result;
} }
@ -154,7 +137,6 @@ class RawEditorState extends EditorState
return; return;
} }
TextSelection selection = widget.controller.selection; TextSelection selection = widget.controller.selection;
assert(selection != null);
TextSelection newSelection = widget.controller.selection; TextSelection newSelection = widget.controller.selection;
@ -210,19 +192,20 @@ class RawEditorState extends EditorState
TextPosition originPosition = TextPosition( TextPosition originPosition = TextPosition(
offset: upKey ? selection.baseOffset : selection.extentOffset); offset: upKey ? selection.baseOffset : selection.extentOffset);
RenderEditableBox child = getRenderEditor().childAtPosition(originPosition); RenderEditableBox child =
getRenderEditor()!.childAtPosition(originPosition);
TextPosition localPosition = TextPosition( TextPosition localPosition = TextPosition(
offset: offset:
originPosition.offset - child.getContainer().getDocumentOffset()); originPosition.offset - child.getContainer().getDocumentOffset());
TextPosition position = upKey TextPosition? position = upKey
? child.getPositionAbove(localPosition) ? child.getPositionAbove(localPosition)
: child.getPositionBelow(localPosition); : child.getPositionBelow(localPosition);
if (position == null) { if (position == null) {
var sibling = upKey var sibling = upKey
? getRenderEditor().childBefore(child) ? getRenderEditor()!.childBefore(child)
: getRenderEditor().childAfter(child); : getRenderEditor()!.childAfter(child);
if (sibling == null) { if (sibling == null) {
position = TextPosition(offset: upKey ? 0 : plainText.length - 1); position = TextPosition(offset: upKey ? 0 : plainText.length - 1);
} else { } else {
@ -273,20 +256,20 @@ class RawEditorState extends EditorState
bool shift) { bool shift) {
if (wordModifier) { if (wordModifier) {
if (leftKey) { if (leftKey) {
TextSelection textSelection = getRenderEditor().selectWordAtPosition( TextSelection textSelection = getRenderEditor()!.selectWordAtPosition(
TextPosition( TextPosition(
offset: _previousCharacter( offset: _previousCharacter(
newSelection.extentOffset, plainText, false))); newSelection.extentOffset, plainText, false)));
return newSelection.copyWith(extentOffset: textSelection.baseOffset); return newSelection.copyWith(extentOffset: textSelection.baseOffset);
} }
TextSelection textSelection = getRenderEditor().selectWordAtPosition( TextSelection textSelection = getRenderEditor()!.selectWordAtPosition(
TextPosition( TextPosition(
offset: offset:
_nextCharacter(newSelection.extentOffset, plainText, false))); _nextCharacter(newSelection.extentOffset, plainText, false)));
return newSelection.copyWith(extentOffset: textSelection.extentOffset); return newSelection.copyWith(extentOffset: textSelection.extentOffset);
} else if (lineModifier) { } else if (lineModifier) {
if (leftKey) { if (leftKey) {
TextSelection textSelection = getRenderEditor().selectLineAtPosition( TextSelection textSelection = getRenderEditor()!.selectLineAtPosition(
TextPosition( TextPosition(
offset: _previousCharacter( offset: _previousCharacter(
newSelection.extentOffset, plainText, false))); newSelection.extentOffset, plainText, false)));
@ -294,7 +277,7 @@ class RawEditorState extends EditorState
} }
int startPoint = newSelection.extentOffset; int startPoint = newSelection.extentOffset;
if (startPoint < plainText.length) { if (startPoint < plainText.length) {
TextSelection textSelection = getRenderEditor() TextSelection textSelection = getRenderEditor()!
.selectLineAtPosition(TextPosition(offset: startPoint)); .selectLineAtPosition(TextPosition(offset: startPoint));
return newSelection.copyWith(extentOffset: textSelection.extentOffset); return newSelection.copyWith(extentOffset: textSelection.extentOffset);
} }
@ -352,7 +335,7 @@ class RawEditorState extends EditorState
} }
int count = 0; int count = 0;
int lastNonWhitespace; int? lastNonWhitespace;
for (String currentString in string.characters) { for (String currentString in string.characters) {
if (!includeWhitespace && if (!includeWhitespace &&
!WHITE_SPACE.contains( !WHITE_SPACE.contains(
@ -368,7 +351,7 @@ class RawEditorState extends EditorState
} }
bool get hasConnection => bool get hasConnection =>
_textInputConnection != null && _textInputConnection.attached; _textInputConnection != null && _textInputConnection!.attached;
openConnectionIfNeeded() { openConnectionIfNeeded() {
if (widget.readOnly) { if (widget.readOnly) {
@ -390,17 +373,17 @@ class RawEditorState extends EditorState
), ),
); );
_textInputConnection.setEditingState(_lastKnownRemoteTextEditingValue); _textInputConnection!.setEditingState(_lastKnownRemoteTextEditingValue!);
// _sentRemoteValues.add(_lastKnownRemoteTextEditingValue); // _sentRemoteValues.add(_lastKnownRemoteTextEditingValue);
} }
_textInputConnection.show(); _textInputConnection!.show();
} }
closeConnectionIfNeeded() { closeConnectionIfNeeded() {
if (!hasConnection) { if (!hasConnection) {
return; return;
} }
_textInputConnection.close(); _textInputConnection!.close();
_textInputConnection = null; _textInputConnection = null;
_lastKnownRemoteTextEditingValue = null; _lastKnownRemoteTextEditingValue = null;
_sentRemoteValues.clear(); _sentRemoteValues.clear();
@ -412,7 +395,7 @@ class RawEditorState extends EditorState
} }
TextEditingValue actualValue = textEditingValue.copyWith( TextEditingValue actualValue = textEditingValue.copyWith(
composing: _lastKnownRemoteTextEditingValue.composing, composing: _lastKnownRemoteTextEditingValue!.composing,
); );
if (actualValue == _lastKnownRemoteTextEditingValue) { if (actualValue == _lastKnownRemoteTextEditingValue) {
@ -420,9 +403,9 @@ class RawEditorState extends EditorState
} }
bool shouldRemember = bool shouldRemember =
textEditingValue.text != _lastKnownRemoteTextEditingValue.text; textEditingValue.text != _lastKnownRemoteTextEditingValue!.text;
_lastKnownRemoteTextEditingValue = actualValue; _lastKnownRemoteTextEditingValue = actualValue;
_textInputConnection.setEditingState(actualValue); _textInputConnection!.setEditingState(actualValue);
if (shouldRemember) { if (shouldRemember) {
_sentRemoteValues.add(actualValue); _sentRemoteValues.add(actualValue);
} }
@ -430,10 +413,10 @@ class RawEditorState extends EditorState
@override @override
TextEditingValue get currentTextEditingValue => TextEditingValue get currentTextEditingValue =>
_lastKnownRemoteTextEditingValue; _lastKnownRemoteTextEditingValue!;
@override @override
AutofillScope get currentAutofillScope => null; AutofillScope? get currentAutofillScope => null;
@override @override
void updateEditingValue(TextEditingValue value) { void updateEditingValue(TextEditingValue value) {
@ -450,13 +433,14 @@ class RawEditorState extends EditorState
return; return;
} }
if (_lastKnownRemoteTextEditingValue.text == value.text && if (_lastKnownRemoteTextEditingValue!.text == value.text &&
_lastKnownRemoteTextEditingValue.selection == value.selection) { _lastKnownRemoteTextEditingValue!.selection == value.selection) {
_lastKnownRemoteTextEditingValue = value; _lastKnownRemoteTextEditingValue = value;
return; return;
} }
TextEditingValue effectiveLastKnownValue = _lastKnownRemoteTextEditingValue; TextEditingValue effectiveLastKnownValue =
_lastKnownRemoteTextEditingValue!;
_lastKnownRemoteTextEditingValue = value; _lastKnownRemoteTextEditingValue = value;
String oldText = effectiveLastKnownValue.text; String oldText = effectiveLastKnownValue.text;
String text = value.text; String text = value.text;
@ -500,7 +484,7 @@ class RawEditorState extends EditorState
if (!hasConnection) { if (!hasConnection) {
return; return;
} }
_textInputConnection.connectionClosedReceived(); _textInputConnection!.connectionClosedReceived();
_textInputConnection = null; _textInputConnection = null;
_lastKnownRemoteTextEditingValue = null; _lastKnownRemoteTextEditingValue = null;
_sentRemoteValues.clear(); _sentRemoteValues.clear();
@ -509,13 +493,11 @@ class RawEditorState extends EditorState
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
assert(debugCheckHasMediaQuery(context)); assert(debugCheckHasMediaQuery(context));
_focusAttachment.reparent(); _focusAttachment!.reparent();
super.build(context); super.build(context);
Document _doc = widget.controller.document; Document _doc = widget.controller.document;
if (_doc.isEmpty() && if (_doc.isEmpty() && !widget.focusNode.hasFocus) {
!widget.focusNode.hasFocus &&
widget.placeholder != null) {
_doc = Document.fromJson(jsonDecode( _doc = Document.fromJson(jsonDecode(
'[{"attributes":{"placeholder":true},"insert":"${widget.placeholder}\\n"}]')); '[{"attributes":{"placeholder":true},"insert":"${widget.placeholder}\\n"}]'));
} }
@ -540,9 +522,9 @@ class RawEditorState extends EditorState
if (widget.scrollable) { if (widget.scrollable) {
EdgeInsets baselinePadding = EdgeInsets baselinePadding =
EdgeInsets.only(top: _styles.paragraph.verticalSpacing.item1); EdgeInsets.only(top: _styles!.paragraph!.verticalSpacing.item1);
child = BaselineProxy( child = BaselineProxy(
textStyle: _styles.paragraph.style, textStyle: _styles!.paragraph!.style,
padding: baselinePadding, padding: baselinePadding,
child: SingleChildScrollView( child: SingleChildScrollView(
controller: _scrollController, controller: _scrollController,
@ -555,11 +537,10 @@ class RawEditorState extends EditorState
BoxConstraints constraints = widget.expands BoxConstraints constraints = widget.expands
? BoxConstraints.expand() ? BoxConstraints.expand()
: BoxConstraints( : BoxConstraints(
minHeight: widget.minHeight ?? 0.0, minHeight: widget.minHeight, maxHeight: widget.maxHeight);
maxHeight: widget.maxHeight ?? double.infinity);
return QuillStyles( return QuillStyles(
data: _styles, data: _styles!,
child: MouseRegion( child: MouseRegion(
cursor: SystemMouseCursors.text, cursor: SystemMouseCursors.text,
child: Container( child: Container(
@ -594,17 +575,18 @@ class RawEditorState extends EditorState
EditableTextBlock editableTextBlock = EditableTextBlock( EditableTextBlock editableTextBlock = EditableTextBlock(
node, node,
_textDirection, _textDirection,
_getVerticalSpacingForBlock(node, _styles), _getVerticalSpacingForBlock(node, _styles!),
widget.controller.selection, widget.controller.selection,
widget.selectionColor, widget.selectionColor,
_styles, _styles!,
widget.enableInteractiveSelection, widget.enableInteractiveSelection,
_hasFocus, _hasFocus,
attrs.containsKey(Attribute.codeBlock.key) attrs.containsKey(Attribute.codeBlock.key)
? EdgeInsets.all(16.0) ? EdgeInsets.all(16.0)
: null, : EdgeInsets.all(
0.0), //CANNOT BE NULL - there's an assert in text_block.dart
widget.embedBuilder, widget.embedBuilder,
_cursorCont, _cursorCont!,
indentLevelCounts); indentLevelCounts);
result.add(editableTextBlock); result.add(editableTextBlock);
} else { } else {
@ -620,21 +602,21 @@ class RawEditorState extends EditorState
line: node, line: node,
textDirection: _textDirection, textDirection: _textDirection,
embedBuilder: widget.embedBuilder, embedBuilder: widget.embedBuilder,
styles: _styles, styles: _styles!,
); );
EditableTextLine editableTextLine = EditableTextLine( EditableTextLine editableTextLine = EditableTextLine(
node, node,
null, null,
textLine, textLine,
0, 0,
_getVerticalSpacingForLine(node, _styles), _getVerticalSpacingForLine(node, _styles!),
_textDirection, _textDirection,
widget.controller.selection, widget.controller.selection,
widget.selectionColor, widget.selectionColor,
widget.enableInteractiveSelection, widget.enableInteractiveSelection,
_hasFocus, _hasFocus,
MediaQuery.of(context).devicePixelRatio, MediaQuery.of(context).devicePixelRatio,
_cursorCont); _cursorCont!);
return editableTextLine; return editableTextLine;
} }
@ -642,54 +624,49 @@ class RawEditorState extends EditorState
Line line, DefaultStyles defaultStyles) { Line line, DefaultStyles defaultStyles) {
Map<String, Attribute> attrs = line.style.attributes; Map<String, Attribute> attrs = line.style.attributes;
if (attrs.containsKey(Attribute.header.key)) { if (attrs.containsKey(Attribute.header.key)) {
int level = attrs[Attribute.header.key].value; int level = attrs[Attribute.header.key]!.value;
switch (level) { switch (level) {
case 1: case 1:
return defaultStyles.h1.verticalSpacing; return defaultStyles.h1!.verticalSpacing;
case 2: case 2:
return defaultStyles.h2.verticalSpacing; return defaultStyles.h2!.verticalSpacing;
case 3: case 3:
return defaultStyles.h3.verticalSpacing; return defaultStyles.h3!.verticalSpacing;
default: default:
throw ('Invalid level $level'); throw ('Invalid level $level');
} }
} }
return defaultStyles.paragraph.verticalSpacing; return defaultStyles.paragraph!.verticalSpacing;
} }
Tuple2<double, double> _getVerticalSpacingForBlock( Tuple2<double, double> _getVerticalSpacingForBlock(
Block node, DefaultStyles defaultStyles) { Block node, DefaultStyles defaultStyles) {
Map<String, Attribute> attrs = node.style.attributes; Map<String, Attribute> attrs = node.style.attributes;
if (attrs.containsKey(Attribute.blockQuote.key)) { if (attrs.containsKey(Attribute.blockQuote.key)) {
return defaultStyles.quote.verticalSpacing; return defaultStyles.quote!.verticalSpacing;
} else if (attrs.containsKey(Attribute.codeBlock.key)) { } else if (attrs.containsKey(Attribute.codeBlock.key)) {
return defaultStyles.code.verticalSpacing; return defaultStyles.code!.verticalSpacing;
} else if (attrs.containsKey(Attribute.indent.key)) { } else if (attrs.containsKey(Attribute.indent.key)) {
return defaultStyles.indent.verticalSpacing; return defaultStyles.indent!.verticalSpacing;
} }
return defaultStyles.lists.verticalSpacing; return defaultStyles.lists!.verticalSpacing;
} }
@override @override
void initState() { void initState() {
super.initState(); super.initState();
_clipboardStatus?.addListener(_onChangedClipboardStatus); _clipboardStatus.addListener(_onChangedClipboardStatus);
widget.controller.addListener(_didChangeTextEditingValue); widget.controller.addListener(_didChangeTextEditingValue);
_scrollController = widget.scrollController ?? ScrollController(); _scrollController = widget.scrollController ?? ScrollController();
_scrollController.addListener(_updateSelectionOverlayForScroll); _scrollController!.addListener(_updateSelectionOverlayForScroll);
_cursorCont = CursorCont( _cursorCont = CursorCont(
show: ValueNotifier<bool>(widget.showCursor ?? false), show: ValueNotifier<bool>(widget.showCursor),
style: widget.cursorStyle ?? style: widget.cursorStyle,
CursorStyle(
color: Colors.blueAccent,
backgroundColor: Colors.grey,
width: 2.0,
),
tickerProvider: this, tickerProvider: this,
); );
@ -707,7 +684,7 @@ class RawEditorState extends EditorState
} else { } else {
_keyboardVisibilityController = KeyboardVisibilityController(); _keyboardVisibilityController = KeyboardVisibilityController();
_keyboardVisibilitySubscription = _keyboardVisibilitySubscription =
_keyboardVisibilityController.onChange.listen((bool visible) { _keyboardVisibilityController!.onChange.listen((bool visible) {
_keyboardVisible = visible; _keyboardVisible = visible;
if (visible) { if (visible) {
_onChangeTextEditingValue(); _onChangeTextEditingValue();
@ -716,21 +693,21 @@ class RawEditorState extends EditorState
} }
_focusAttachment = widget.focusNode.attach(context, _focusAttachment = widget.focusNode.attach(context,
onKey: (node, event) => _keyboardListener.handleRawKeyEvent(event)); onKey: (node, event) => _keyboardListener!.handleRawKeyEvent(event));
widget.focusNode.addListener(_handleFocusChanged); widget.focusNode.addListener(_handleFocusChanged);
} }
@override @override
didChangeDependencies() { didChangeDependencies() {
super.didChangeDependencies(); super.didChangeDependencies();
DefaultStyles parentStyles = QuillStyles.getStyles(context, true); DefaultStyles? parentStyles = QuillStyles.getStyles(context, true);
DefaultStyles defaultStyles = DefaultStyles.getInstance(context); DefaultStyles defaultStyles = DefaultStyles.getInstance(context);
_styles = (parentStyles != null) _styles = (parentStyles != null)
? defaultStyles.merge(parentStyles) ? defaultStyles.merge(parentStyles)
: defaultStyles; : defaultStyles;
if (widget.customStyles != null) { if (widget.customStyles != null) {
_styles = _styles.merge(widget.customStyles); _styles = _styles!.merge(widget.customStyles!);
} }
if (!_didAutoFocus && widget.autoFocus) { if (!_didAutoFocus && widget.autoFocus) {
@ -743,8 +720,8 @@ class RawEditorState extends EditorState
void didUpdateWidget(RawEditor oldWidget) { void didUpdateWidget(RawEditor oldWidget) {
super.didUpdateWidget(oldWidget); super.didUpdateWidget(oldWidget);
_cursorCont.show.value = widget.showCursor; _cursorCont!.show.value = widget.showCursor;
_cursorCont.style = widget.cursorStyle; _cursorCont!.style = widget.cursorStyle;
if (widget.controller != oldWidget.controller) { if (widget.controller != oldWidget.controller) {
oldWidget.controller.removeListener(_didChangeTextEditingValue); oldWidget.controller.removeListener(_didChangeTextEditingValue);
@ -754,16 +731,16 @@ class RawEditorState extends EditorState
if (widget.scrollController != null && if (widget.scrollController != null &&
widget.scrollController != _scrollController) { widget.scrollController != _scrollController) {
_scrollController.removeListener(_updateSelectionOverlayForScroll); _scrollController!.removeListener(_updateSelectionOverlayForScroll);
_scrollController = widget.scrollController; _scrollController = widget.scrollController;
_scrollController.addListener(_updateSelectionOverlayForScroll); _scrollController!.addListener(_updateSelectionOverlayForScroll);
} }
if (widget.focusNode != oldWidget.focusNode) { if (widget.focusNode != oldWidget.focusNode) {
oldWidget.focusNode.removeListener(_handleFocusChanged); oldWidget.focusNode.removeListener(_handleFocusChanged);
_focusAttachment?.detach(); _focusAttachment?.detach();
_focusAttachment = widget.focusNode.attach(context, _focusAttachment = widget.focusNode.attach(context,
onKey: (node, event) => _keyboardListener.handleRawKeyEvent(event)); onKey: (node, event) => _keyboardListener!.handleRawKeyEvent(event));
widget.focusNode.addListener(_handleFocusChanged); widget.focusNode.addListener(_handleFocusChanged);
updateKeepAlive(); updateKeepAlive();
} }
@ -790,7 +767,6 @@ class RawEditorState extends EditorState
handleDelete(bool forward) { handleDelete(bool forward) {
TextSelection selection = widget.controller.selection; TextSelection selection = widget.controller.selection;
String plainText = textEditingValue.text; String plainText = textEditingValue.text;
assert(selection != null);
int cursorPosition = selection.start; int cursorPosition = selection.start;
String textBefore = selection.textBefore(plainText); String textBefore = selection.textBefore(plainText);
String textAfter = selection.textAfter(plainText); String textAfter = selection.textAfter(plainText);
@ -820,7 +796,6 @@ class RawEditorState extends EditorState
Future<void> handleShortcut(InputShortcut shortcut) async { Future<void> handleShortcut(InputShortcut shortcut) async {
TextSelection selection = widget.controller.selection; TextSelection selection = widget.controller.selection;
assert(selection != null);
String plainText = textEditingValue.text; String plainText = textEditingValue.text;
if (shortcut == InputShortcut.COPY) { if (shortcut == InputShortcut.COPY) {
if (!selection.isCollapsed) { if (!selection.isCollapsed) {
@ -849,13 +824,14 @@ class RawEditorState extends EditorState
return; return;
} }
if (shortcut == InputShortcut.PASTE && !widget.readOnly) { if (shortcut == InputShortcut.PASTE && !widget.readOnly) {
ClipboardData data = await Clipboard.getData(Clipboard.kTextPlain); ClipboardData? data = await Clipboard.getData(Clipboard.kTextPlain);
if (data != null) { if (data != null) {
widget.controller.replaceText( widget.controller.replaceText(
selection.start, selection.start,
selection.end - selection.start, selection.end - selection.start,
data.text, data.text as String,
TextSelection.collapsed(offset: selection.start + data.text.length), TextSelection.collapsed(
offset: selection.start + (data.text as String).length),
); );
} }
return; return;
@ -881,10 +857,10 @@ class RawEditorState extends EditorState
_selectionOverlay = null; _selectionOverlay = null;
widget.controller.removeListener(_didChangeTextEditingValue); widget.controller.removeListener(_didChangeTextEditingValue);
widget.focusNode.removeListener(_handleFocusChanged); widget.focusNode.removeListener(_handleFocusChanged);
_focusAttachment.detach(); _focusAttachment!.detach();
_cursorCont.dispose(); _cursorCont!.dispose();
_clipboardStatus?.removeListener(_onChangedClipboardStatus); _clipboardStatus.removeListener(_onChangedClipboardStatus);
_clipboardStatus?.dispose(); _clipboardStatus.dispose();
super.dispose(); super.dispose();
} }
@ -909,14 +885,14 @@ class RawEditorState extends EditorState
_onChangeTextEditingValue() { _onChangeTextEditingValue() {
_showCaretOnScreen(); _showCaretOnScreen();
updateRemoteValueIfNeeded(); updateRemoteValueIfNeeded();
_cursorCont.startOrStopCursorTimerIfNeeded( _cursorCont!
_hasFocus, widget.controller.selection); .startOrStopCursorTimerIfNeeded(_hasFocus, widget.controller.selection);
if (hasConnection) { if (hasConnection) {
_cursorCont.stopCursorTimer(resetCharTicks: false); _cursorCont!.stopCursorTimer(resetCharTicks: false);
_cursorCont.startCursorTimer(); _cursorCont!.startCursorTimer();
} }
SchedulerBinding.instance.addPostFrameCallback( SchedulerBinding.instance!.addPostFrameCallback(
(Duration _) => _updateOrDisposeSelectionOverlayIfNeeded()); (Duration _) => _updateOrDisposeSelectionOverlayIfNeeded());
if (!mounted) return; if (!mounted) return;
setState(() { setState(() {
@ -928,9 +904,9 @@ class RawEditorState extends EditorState
_updateOrDisposeSelectionOverlayIfNeeded() { _updateOrDisposeSelectionOverlayIfNeeded() {
if (_selectionOverlay != null) { if (_selectionOverlay != null) {
if (_hasFocus) { if (_hasFocus) {
_selectionOverlay.update(textEditingValue); _selectionOverlay!.update(textEditingValue);
} else { } else {
_selectionOverlay.dispose(); _selectionOverlay!.dispose();
_selectionOverlay = null; _selectionOverlay = null;
} }
} else if (_hasFocus) { } else if (_hasFocus) {
@ -952,22 +928,22 @@ class RawEditorState extends EditorState
DragStartBehavior.start, DragStartBehavior.start,
null, null,
_clipboardStatus); _clipboardStatus);
_selectionOverlay.handlesVisible = _shouldShowSelectionHandles(); _selectionOverlay!.handlesVisible = _shouldShowSelectionHandles();
_selectionOverlay.showHandles(); _selectionOverlay!.showHandles();
} }
} }
} }
_handleFocusChanged() { _handleFocusChanged() {
openOrCloseConnection(); openOrCloseConnection();
_cursorCont.startOrStopCursorTimerIfNeeded( _cursorCont!
_hasFocus, widget.controller.selection); .startOrStopCursorTimerIfNeeded(_hasFocus, widget.controller.selection);
_updateOrDisposeSelectionOverlayIfNeeded(); _updateOrDisposeSelectionOverlayIfNeeded();
if (_hasFocus) { if (_hasFocus) {
WidgetsBinding.instance.addObserver(this); WidgetsBinding.instance!.addObserver(this);
_showCaretOnScreen(); _showCaretOnScreen();
} else { } else {
WidgetsBinding.instance.removeObserver(this); WidgetsBinding.instance!.removeObserver(this);
} }
updateKeepAlive(); updateKeepAlive();
} }
@ -988,23 +964,23 @@ class RawEditorState extends EditorState
} }
_showCaretOnScreenScheduled = true; _showCaretOnScreenScheduled = true;
SchedulerBinding.instance.addPostFrameCallback((Duration _) { SchedulerBinding.instance!.addPostFrameCallback((Duration _) {
_showCaretOnScreenScheduled = false; _showCaretOnScreenScheduled = false;
final viewport = RenderAbstractViewport.of(getRenderEditor()); final viewport = RenderAbstractViewport.of(getRenderEditor());
assert(viewport != null); assert(viewport != null);
final editorOffset = final editorOffset = getRenderEditor()!
getRenderEditor().localToGlobal(Offset(0.0, 0.0), ancestor: viewport); .localToGlobal(Offset(0.0, 0.0), ancestor: viewport);
final offsetInViewport = _scrollController.offset + editorOffset.dy; final offsetInViewport = _scrollController!.offset + editorOffset.dy;
final offset = getRenderEditor().getOffsetToRevealCursor( final offset = getRenderEditor()!.getOffsetToRevealCursor(
_scrollController.position.viewportDimension, _scrollController!.position.viewportDimension,
_scrollController.offset, _scrollController!.offset,
offsetInViewport, offsetInViewport,
); );
if (offset != null) { if (offset != null) {
_scrollController.animateTo( _scrollController!.animateTo(
offset, offset,
duration: Duration(milliseconds: 100), duration: Duration(milliseconds: 100),
curve: Curves.fastOutSlowIn, curve: Curves.fastOutSlowIn,
@ -1014,12 +990,12 @@ class RawEditorState extends EditorState
} }
@override @override
RenderEditor getRenderEditor() { RenderEditor? getRenderEditor() {
return _editorKey.currentContext.findRenderObject(); return _editorKey.currentContext!.findRenderObject() as RenderEditor?;
} }
@override @override
EditorTextSelectionOverlay getSelectionOverlay() { EditorTextSelectionOverlay? getSelectionOverlay() {
return _selectionOverlay; return _selectionOverlay;
} }
@ -1075,37 +1051,38 @@ class RawEditorState extends EditorState
); );
} else { } else {
final TextEditingValue value = textEditingValue; final TextEditingValue value = textEditingValue;
final ClipboardData data = await Clipboard.getData(Clipboard.kTextPlain); final ClipboardData? data = await Clipboard.getData(Clipboard.kTextPlain);
if (data != null) { if (data != null) {
final length = final length =
textEditingValue.selection.end - textEditingValue.selection.start; textEditingValue.selection.end - textEditingValue.selection.start;
widget.controller.replaceText( widget.controller.replaceText(
value.selection.start, value.selection.start,
length, length,
data.text, data.text as String,
value.selection, value.selection,
); );
// move cursor to the end of pasted text selection // move cursor to the end of pasted text selection
widget.controller.updateSelection( widget.controller.updateSelection(
TextSelection.collapsed( TextSelection.collapsed(
offset: value.selection.start + data.text.length), offset: value.selection.start + (data.text as String).length),
ChangeSource.LOCAL); ChangeSource.LOCAL);
} }
} }
} }
Future<bool> __isItCut(TextEditingValue value) async { Future<bool> __isItCut(TextEditingValue value) async {
final ClipboardData data = await Clipboard.getData(Clipboard.kTextPlain); final ClipboardData? data = await Clipboard.getData(Clipboard.kTextPlain);
return textEditingValue.text.length - value.text.length == data.text.length; return textEditingValue.text.length - value.text.length ==
(data!.text as String).length;
} }
@override @override
bool showToolbar() { bool showToolbar() {
if (_selectionOverlay == null || _selectionOverlay.toolbar != null) { if (_selectionOverlay == null || _selectionOverlay!.toolbar != null) {
return false; return false;
} }
_selectionOverlay.showToolbar(); _selectionOverlay!.showToolbar();
return true; return true;
} }
@ -1123,15 +1100,15 @@ class RawEditorState extends EditorState
class _Editor extends MultiChildRenderObjectWidget { class _Editor extends MultiChildRenderObjectWidget {
_Editor({ _Editor({
@required Key key, required Key key,
@required List<Widget> children, required List<Widget> children,
@required this.document, required this.document,
@required this.textDirection, required this.textDirection,
@required this.hasFocus, required this.hasFocus,
@required this.selection, required this.selection,
@required this.startHandleLayerLink, required this.startHandleLayerLink,
@required this.endHandleLayerLink, required this.endHandleLayerLink,
@required this.onSelectionChanged, required this.onSelectionChanged,
this.padding = EdgeInsets.zero, this.padding = EdgeInsets.zero,
}) : super(key: key, children: children); }) : super(key: key, children: children);

@ -2,12 +2,12 @@ import 'package:flutter/material.dart';
class ResponsiveWidget extends StatelessWidget { class ResponsiveWidget extends StatelessWidget {
final Widget largeScreen; final Widget largeScreen;
final Widget mediumScreen; final Widget? mediumScreen;
final Widget smallScreen; final Widget? smallScreen;
const ResponsiveWidget( const ResponsiveWidget(
{Key key, {Key? key,
@required this.largeScreen, required this.largeScreen,
this.mediumScreen, this.mediumScreen,
this.smallScreen}) this.smallScreen})
: super(key: key); : super(key: key);

@ -50,11 +50,11 @@ const List<String> romanNumbers = [
class EditableTextBlock extends StatelessWidget { class EditableTextBlock extends StatelessWidget {
final Block block; final Block block;
final TextDirection textDirection; final TextDirection textDirection;
final Tuple2 verticalSpacing; final Tuple2<double, double> verticalSpacing;
final TextSelection textSelection; final TextSelection? textSelection;
final Color color; final Color? color;
final DefaultStyles styles; final DefaultStyles styles;
final bool enableInteractiveSelection; final bool? enableInteractiveSelection;
final bool hasFocus; final bool hasFocus;
final EdgeInsets contentPadding; final EdgeInsets contentPadding;
final EmbedBuilder embedBuilder; final EmbedBuilder embedBuilder;
@ -73,16 +73,13 @@ class EditableTextBlock extends StatelessWidget {
this.contentPadding, this.contentPadding,
this.embedBuilder, this.embedBuilder,
this.cursorCont, this.cursorCont,
this.indentLevelCounts) this.indentLevelCounts);
: assert(hasFocus != null),
assert(embedBuilder != null),
assert(cursorCont != null);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
assert(debugCheckHasMediaQuery(context)); assert(debugCheckHasMediaQuery(context));
DefaultStyles defaultStyles = QuillStyles.getStyles(context, false); DefaultStyles? defaultStyles = QuillStyles.getStyles(context, false);
return _EditableBlock( return _EditableBlock(
block, block,
textDirection, textDirection,
@ -92,25 +89,28 @@ class EditableTextBlock extends StatelessWidget {
_buildChildren(context, this.indentLevelCounts)); _buildChildren(context, this.indentLevelCounts));
} }
BoxDecoration _getDecorationForBlock( BoxDecoration? _getDecorationForBlock(
Block node, DefaultStyles defaultStyles) { Block node, DefaultStyles? defaultStyles) {
if (defaultStyles == null) {
return null;
}
Map<String, Attribute> attrs = block.style.attributes; Map<String, Attribute> attrs = block.style.attributes;
if (attrs.containsKey(Attribute.blockQuote.key)) { if (attrs.containsKey(Attribute.blockQuote.key)) {
return defaultStyles.quote.decoration; return defaultStyles.quote!.decoration;
} }
if (attrs.containsKey(Attribute.codeBlock.key)) { if (attrs.containsKey(Attribute.codeBlock.key)) {
return defaultStyles.code.decoration; return defaultStyles.code!.decoration;
} }
return null; return null;
} }
List<Widget> _buildChildren( List<Widget> _buildChildren(
BuildContext context, Map<int, int> indentLevelCounts) { BuildContext context, Map<int, int> indentLevelCounts) {
DefaultStyles defaultStyles = QuillStyles.getStyles(context, false); DefaultStyles? defaultStyles = QuillStyles.getStyles(context, false);
int count = block.children.length; int count = block.children.length;
var children = <Widget>[]; var children = <Widget>[];
int index = 0; int index = 0;
for (Line line in block.children) { for (Line line in block.children as List<Line>) {
index++; index++;
EditableTextLine editableTextLine = EditableTextLine( EditableTextLine editableTextLine = EditableTextLine(
line, line,
@ -122,11 +122,11 @@ class EditableTextBlock extends StatelessWidget {
styles: styles, styles: styles,
), ),
_getIndentWidth(), _getIndentWidth(),
_getSpacingForLine(line, index, count, defaultStyles), _getSpacingForLine(line, index, count, defaultStyles!),
textDirection, textDirection,
textSelection, textSelection!,
color, color!,
enableInteractiveSelection, enableInteractiveSelection!,
hasFocus, hasFocus,
MediaQuery.of(context).devicePixelRatio, MediaQuery.of(context).devicePixelRatio,
cursorCont); cursorCont);
@ -135,16 +135,16 @@ class EditableTextBlock extends StatelessWidget {
return children.toList(growable: false); return children.toList(growable: false);
} }
Widget _buildLeading(BuildContext context, Line line, int index, Widget? _buildLeading(BuildContext context, Line line, int index,
Map<int, int> indentLevelCounts, int count) { Map<int, int> indentLevelCounts, int count) {
DefaultStyles defaultStyles = QuillStyles.getStyles(context, false); DefaultStyles? defaultStyles = QuillStyles.getStyles(context, false);
Map<String, Attribute> attrs = line.style.attributes; Map<String, Attribute> attrs = line.style.attributes;
if (attrs[Attribute.list.key] == Attribute.ol) { if (attrs[Attribute.list.key] == Attribute.ol) {
return _NumberPoint( return _NumberPoint(
index: index, index: index,
indentLevelCounts: indentLevelCounts, indentLevelCounts: indentLevelCounts,
count: count, count: count,
style: defaultStyles.paragraph.style, style: defaultStyles!.paragraph!.style,
attrs: attrs, attrs: attrs,
width: 32.0, width: 32.0,
padding: 8.0, padding: 8.0,
@ -153,20 +153,20 @@ class EditableTextBlock extends StatelessWidget {
if (attrs[Attribute.list.key] == Attribute.ul) { if (attrs[Attribute.list.key] == Attribute.ul) {
return _BulletPoint( return _BulletPoint(
style: style: defaultStyles!.paragraph!.style
defaultStyles.paragraph.style.copyWith(fontWeight: FontWeight.bold), .copyWith(fontWeight: FontWeight.bold),
width: 32, width: 32,
); );
} }
if (attrs[Attribute.list.key] == Attribute.checked) { if (attrs[Attribute.list.key] == Attribute.checked) {
return _Checkbox( return _Checkbox(
style: defaultStyles.paragraph.style, width: 32, isChecked: true); style: defaultStyles!.paragraph!.style, width: 32, isChecked: true);
} }
if (attrs[Attribute.list.key] == Attribute.unchecked) { if (attrs[Attribute.list.key] == Attribute.unchecked) {
return _Checkbox( return _Checkbox(
style: defaultStyles.paragraph.style, width: 32, isChecked: false); style: defaultStyles!.paragraph!.style, width: 32, isChecked: false);
} }
if (attrs.containsKey(Attribute.codeBlock.key)) { if (attrs.containsKey(Attribute.codeBlock.key)) {
@ -174,8 +174,8 @@ class EditableTextBlock extends StatelessWidget {
index: index, index: index,
indentLevelCounts: indentLevelCounts, indentLevelCounts: indentLevelCounts,
count: count, count: count,
style: defaultStyles.code.style style: defaultStyles!.code!.style
.copyWith(color: defaultStyles.code.style.color.withOpacity(0.4)), .copyWith(color: defaultStyles.code!.style.color!.withOpacity(0.4)),
width: 32.0, width: 32.0,
attrs: attrs, attrs: attrs,
padding: 16.0, padding: 16.0,
@ -188,7 +188,7 @@ class EditableTextBlock extends StatelessWidget {
double _getIndentWidth() { double _getIndentWidth() {
Map<String, Attribute> attrs = block.style.attributes; Map<String, Attribute> attrs = block.style.attributes;
Attribute indent = attrs[Attribute.indent.key]; Attribute? indent = attrs[Attribute.indent.key];
double extraIndent = 0.0; double extraIndent = 0.0;
if (indent != null && indent.value != null) { if (indent != null && indent.value != null) {
extraIndent = 16.0 * indent.value; extraIndent = 16.0 * indent.value;
@ -207,37 +207,37 @@ class EditableTextBlock extends StatelessWidget {
Map<String, Attribute> attrs = block.style.attributes; Map<String, Attribute> attrs = block.style.attributes;
if (attrs.containsKey(Attribute.header.key)) { if (attrs.containsKey(Attribute.header.key)) {
int level = attrs[Attribute.header.key].value; int level = attrs[Attribute.header.key]!.value;
switch (level) { switch (level) {
case 1: case 1:
top = defaultStyles.h1.verticalSpacing.item1; top = defaultStyles.h1!.verticalSpacing.item1;
bottom = defaultStyles.h1.verticalSpacing.item2; bottom = defaultStyles.h1!.verticalSpacing.item2;
break; break;
case 2: case 2:
top = defaultStyles.h2.verticalSpacing.item1; top = defaultStyles.h2!.verticalSpacing.item1;
bottom = defaultStyles.h2.verticalSpacing.item2; bottom = defaultStyles.h2!.verticalSpacing.item2;
break; break;
case 3: case 3:
top = defaultStyles.h3.verticalSpacing.item1; top = defaultStyles.h3!.verticalSpacing.item1;
bottom = defaultStyles.h3.verticalSpacing.item2; bottom = defaultStyles.h3!.verticalSpacing.item2;
break; break;
default: default:
throw ('Invalid level $level'); throw ('Invalid level $level');
} }
} else { } else {
Tuple2 lineSpacing; Tuple2? lineSpacing;
if (attrs.containsKey(Attribute.blockQuote.key)) { if (attrs.containsKey(Attribute.blockQuote.key)) {
lineSpacing = defaultStyles.quote.lineSpacing; lineSpacing = defaultStyles.quote!.lineSpacing;
} else if (attrs.containsKey(Attribute.indent.key)) { } else if (attrs.containsKey(Attribute.indent.key)) {
lineSpacing = defaultStyles.indent.lineSpacing; lineSpacing = defaultStyles.indent!.lineSpacing;
} else if (attrs.containsKey(Attribute.list.key)) { } else if (attrs.containsKey(Attribute.list.key)) {
lineSpacing = defaultStyles.lists.lineSpacing; lineSpacing = defaultStyles.lists!.lineSpacing;
} else if (attrs.containsKey(Attribute.codeBlock.key)) { } else if (attrs.containsKey(Attribute.codeBlock.key)) {
lineSpacing = defaultStyles.code.lineSpacing; lineSpacing = defaultStyles.code!.lineSpacing;
} else if (attrs.containsKey(Attribute.align.key)) { } else if (attrs.containsKey(Attribute.align.key)) {
lineSpacing = defaultStyles.align.lineSpacing; lineSpacing = defaultStyles.align!.lineSpacing;
} }
top = lineSpacing.item1; top = lineSpacing!.item1;
bottom = lineSpacing.item2; bottom = lineSpacing.item2;
} }
@ -256,19 +256,14 @@ class EditableTextBlock extends StatelessWidget {
class RenderEditableTextBlock extends RenderEditableContainerBox class RenderEditableTextBlock extends RenderEditableContainerBox
implements RenderEditableBox { implements RenderEditableBox {
RenderEditableTextBlock({ RenderEditableTextBlock({
List<RenderEditableBox> children, List<RenderEditableBox>? children,
@required Block block, required Block block,
@required TextDirection textDirection, required TextDirection textDirection,
@required EdgeInsetsGeometry padding, required EdgeInsetsGeometry padding,
@required Decoration decoration, required Decoration decoration,
ImageConfiguration configuration = ImageConfiguration.empty, ImageConfiguration configuration = ImageConfiguration.empty,
EdgeInsets contentPadding = EdgeInsets.zero, EdgeInsets contentPadding = EdgeInsets.zero,
}) : assert(block != null), }) : _decoration = decoration,
assert(textDirection != null),
assert(decoration != null),
assert(padding != null),
assert(contentPadding != null),
_decoration = decoration,
_configuration = configuration, _configuration = configuration,
_savedPadding = padding, _savedPadding = padding,
_contentPadding = contentPadding, _contentPadding = contentPadding,
@ -283,7 +278,6 @@ class RenderEditableTextBlock extends RenderEditableContainerBox
EdgeInsets _contentPadding; EdgeInsets _contentPadding;
set contentPadding(EdgeInsets value) { set contentPadding(EdgeInsets value) {
assert(value != null);
if (_contentPadding == value) return; if (_contentPadding == value) return;
_contentPadding = value; _contentPadding = value;
super.setPadding(_savedPadding.add(_contentPadding)); super.setPadding(_savedPadding.add(_contentPadding));
@ -295,13 +289,12 @@ class RenderEditableTextBlock extends RenderEditableContainerBox
_savedPadding = value; _savedPadding = value;
} }
BoxPainter _painter; BoxPainter? _painter;
Decoration get decoration => _decoration; Decoration get decoration => _decoration;
Decoration _decoration; Decoration _decoration;
set decoration(Decoration value) { set decoration(Decoration value) {
assert(value != null);
if (value == _decoration) return; if (value == _decoration) return;
_painter?.dispose(); _painter?.dispose();
_painter = null; _painter = null;
@ -313,7 +306,6 @@ class RenderEditableTextBlock extends RenderEditableContainerBox
ImageConfiguration _configuration; ImageConfiguration _configuration;
set configuration(ImageConfiguration value) { set configuration(ImageConfiguration value) {
assert(value != null);
if (value == _configuration) return; if (value == _configuration) return;
_configuration = value; _configuration = value;
markNeedsPaint(); markNeedsPaint();
@ -344,8 +336,8 @@ class RenderEditableTextBlock extends RenderEditableContainerBox
@override @override
TextPosition getPositionForOffset(Offset offset) { TextPosition getPositionForOffset(Offset offset) {
RenderEditableBox child = childAtOffset(offset); RenderEditableBox? child = childAtOffset(offset);
BoxParentData parentData = child.parentData; BoxParentData parentData = child!.parentData as BoxParentData;
TextPosition localPosition = TextPosition localPosition =
child.getPositionForOffset(offset - parentData.offset); child.getPositionForOffset(offset - parentData.offset);
return TextPosition( return TextPosition(
@ -367,19 +359,19 @@ class RenderEditableTextBlock extends RenderEditableContainerBox
} }
@override @override
TextPosition getPositionAbove(TextPosition position) { TextPosition? getPositionAbove(TextPosition position) {
assert(position.offset < getContainer().length); assert(position.offset < getContainer().length);
RenderEditableBox child = childAtPosition(position); RenderEditableBox child = childAtPosition(position);
TextPosition childLocalPosition = TextPosition( TextPosition childLocalPosition = TextPosition(
offset: position.offset - child.getContainer().getOffset()); offset: position.offset - child.getContainer().getOffset());
TextPosition result = child.getPositionAbove(childLocalPosition); TextPosition? result = child.getPositionAbove(childLocalPosition);
if (result != null) { if (result != null) {
return TextPosition( return TextPosition(
offset: result.offset + child.getContainer().getOffset()); offset: result.offset + child.getContainer().getOffset());
} }
RenderEditableBox sibling = childBefore(child); RenderEditableBox? sibling = childBefore(child);
if (sibling == null) { if (sibling == null) {
return null; return null;
} }
@ -395,19 +387,19 @@ class RenderEditableTextBlock extends RenderEditableContainerBox
} }
@override @override
TextPosition getPositionBelow(TextPosition position) { TextPosition? getPositionBelow(TextPosition position) {
assert(position.offset < getContainer().length); assert(position.offset < getContainer().length);
RenderEditableBox child = childAtPosition(position); RenderEditableBox child = childAtPosition(position);
TextPosition childLocalPosition = TextPosition( TextPosition childLocalPosition = TextPosition(
offset: position.offset - child.getContainer().getOffset()); offset: position.offset - child.getContainer().getOffset());
TextPosition result = child.getPositionBelow(childLocalPosition); TextPosition? result = child.getPositionBelow(childLocalPosition);
if (result != null) { if (result != null) {
return TextPosition( return TextPosition(
offset: result.offset + child.getContainer().getOffset()); offset: result.offset + child.getContainer().getOffset());
} }
RenderEditableBox sibling = childAfter(child); RenderEditableBox? sibling = childAfter(child);
if (sibling == null) { if (sibling == null) {
return null; return null;
} }
@ -436,7 +428,7 @@ class RenderEditableTextBlock extends RenderEditableContainerBox
null); null);
} }
Node baseNode = getContainer().queryChild(selection.start, false).node; Node? baseNode = getContainer().queryChild(selection.start, false).node;
var baseChild = firstChild; var baseChild = firstChild;
while (baseChild != null) { while (baseChild != null) {
if (baseChild.getContainer() == baseNode) { if (baseChild.getContainer() == baseNode) {
@ -446,7 +438,7 @@ class RenderEditableTextBlock extends RenderEditableContainerBox
} }
assert(baseChild != null); assert(baseChild != null);
TextSelectionPoint basePoint = baseChild.getBaseEndpointForSelection( TextSelectionPoint basePoint = baseChild!.getBaseEndpointForSelection(
localSelection(baseChild.getContainer(), selection, true)); localSelection(baseChild.getContainer(), selection, true));
return TextSelectionPoint( return TextSelectionPoint(
basePoint.point + (baseChild.parentData as BoxParentData).offset, basePoint.point + (baseChild.parentData as BoxParentData).offset,
@ -462,7 +454,7 @@ class RenderEditableTextBlock extends RenderEditableContainerBox
null); null);
} }
Node extentNode = getContainer().queryChild(selection.end, false).node; Node? extentNode = getContainer().queryChild(selection.end, false).node;
var extentChild = firstChild; var extentChild = firstChild;
while (extentChild != null) { while (extentChild != null) {
@ -473,7 +465,7 @@ class RenderEditableTextBlock extends RenderEditableContainerBox
} }
assert(extentChild != null); assert(extentChild != null);
TextSelectionPoint extentPoint = extentChild.getExtentEndpointForSelection( TextSelectionPoint extentPoint = extentChild!.getExtentEndpointForSelection(
localSelection(extentChild.getContainer(), selection, true)); localSelection(extentChild.getContainer(), selection, true));
return TextSelectionPoint( return TextSelectionPoint(
extentPoint.point + (extentChild.parentData as BoxParentData).offset, extentPoint.point + (extentChild.parentData as BoxParentData).offset,
@ -495,11 +487,9 @@ class RenderEditableTextBlock extends RenderEditableContainerBox
} }
_paintDecoration(PaintingContext context, Offset offset) { _paintDecoration(PaintingContext context, Offset offset) {
assert(size.width != null);
assert(size.height != null);
_painter ??= _decoration.createBoxPainter(markNeedsPaint); _painter ??= _decoration.createBoxPainter(markNeedsPaint);
EdgeInsets decorationPadding = resolvedPadding - _contentPadding; EdgeInsets decorationPadding = resolvedPadding! - _contentPadding;
ImageConfiguration filledConfiguration = ImageConfiguration filledConfiguration =
configuration.copyWith(size: decorationPadding.deflateSize(size)); configuration.copyWith(size: decorationPadding.deflateSize(size));
@ -507,7 +497,7 @@ class RenderEditableTextBlock extends RenderEditableContainerBox
final decorationOffset = final decorationOffset =
offset.translate(decorationPadding.left, decorationPadding.top); offset.translate(decorationPadding.left, decorationPadding.top);
_painter.paint(context.canvas, decorationOffset, filledConfiguration); _painter!.paint(context.canvas, decorationOffset, filledConfiguration);
if (debugSaveCount != context.canvas.getSaveCount()) { if (debugSaveCount != context.canvas.getSaveCount()) {
throw ('${_decoration.runtimeType} painter had mismatching save and restore calls.'); throw ('${_decoration.runtimeType} painter had mismatching save and restore calls.');
} }
@ -517,7 +507,7 @@ class RenderEditableTextBlock extends RenderEditableContainerBox
} }
@override @override
bool hitTestChildren(BoxHitTestResult result, {Offset position}) { bool hitTestChildren(BoxHitTestResult result, {required Offset position}) {
return defaultHitTestChildren(result, position: position); return defaultHitTestChildren(result, position: position);
} }
} }
@ -527,16 +517,11 @@ class _EditableBlock extends MultiChildRenderObjectWidget {
final TextDirection textDirection; final TextDirection textDirection;
final Tuple2<double, double> padding; final Tuple2<double, double> padding;
final Decoration decoration; final Decoration decoration;
final EdgeInsets contentPadding; final EdgeInsets? contentPadding;
_EditableBlock(this.block, this.textDirection, this.padding, this.decoration, _EditableBlock(this.block, this.textDirection, this.padding, this.decoration,
this.contentPadding, List<Widget> children) this.contentPadding, List<Widget> children)
: assert(block != null), : super(children: children);
assert(textDirection != null),
assert(padding != null),
assert(decoration != null),
assert(children != null),
super(children: children);
EdgeInsets get _padding => EdgeInsets get _padding =>
EdgeInsets.only(top: padding.item1, bottom: padding.item2); EdgeInsets.only(top: padding.item1, bottom: padding.item2);
@ -576,13 +561,13 @@ class _NumberPoint extends StatelessWidget {
final double padding; final double padding;
const _NumberPoint({ const _NumberPoint({
Key key, Key? key,
@required this.index, required this.index,
@required this.indentLevelCounts, required this.indentLevelCounts,
@required this.count, required this.count,
@required this.style, required this.style,
@required this.width, required this.width,
@required this.attrs, required this.attrs,
this.withDot = true, this.withDot = true,
this.padding = 0.0, this.padding = 0.0,
}) : super(key: key); }) : super(key: key);
@ -602,7 +587,7 @@ class _NumberPoint extends StatelessWidget {
); );
} }
if (this.attrs.containsKey(Attribute.indent.key)) { if (this.attrs.containsKey(Attribute.indent.key)) {
level = this.attrs[Attribute.indent.key].value; level = this.attrs[Attribute.indent.key]!.value;
} else { } else {
// first level but is back from previous indent level // first level but is back from previous indent level
// supposed to be "2." // supposed to be "2."
@ -674,9 +659,9 @@ class _BulletPoint extends StatelessWidget {
final double width; final double width;
const _BulletPoint({ const _BulletPoint({
Key key, Key? key,
@required this.style, required this.style,
@required this.width, required this.width,
}) : super(key: key); }) : super(key: key);
@override @override
@ -691,23 +676,23 @@ class _BulletPoint extends StatelessWidget {
} }
class _Checkbox extends StatefulWidget { class _Checkbox extends StatefulWidget {
final TextStyle style; final TextStyle? style;
final double width; final double? width;
final bool isChecked; final bool? isChecked;
const _Checkbox({Key key, this.style, this.width, this.isChecked}) const _Checkbox({Key? key, this.style, this.width, this.isChecked})
: super(key: key); : super(key: key);
@override @override
__CheckboxState createState() => __CheckboxState(); __CheckboxState createState() => __CheckboxState();
} }
class __CheckboxState extends State<_Checkbox> { class __CheckboxState extends State<_Checkbox> {
bool isChecked; bool? isChecked;
void _onCheckboxClicked(bool newValue) => setState(() { void _onCheckboxClicked(bool? newValue) => setState(() {
isChecked = newValue; isChecked = newValue;
if (isChecked) { if (isChecked!) {
// check list // check list
} else { } else {
// uncheck list // uncheck list

@ -27,12 +27,13 @@ class TextLine extends StatelessWidget {
final EmbedBuilder embedBuilder; final EmbedBuilder embedBuilder;
final DefaultStyles styles; final DefaultStyles styles;
const TextLine( const TextLine({
{Key key, this.line, this.textDirection, this.embedBuilder, this.styles}) Key? key,
: assert(line != null), required this.line,
assert(embedBuilder != null), required this.textDirection,
assert(styles != null), required this.embedBuilder,
super(key: key); required this.styles,
}) : super(key: key);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -45,7 +46,7 @@ class TextLine extends StatelessWidget {
TextSpan textSpan = _buildTextSpan(context); TextSpan textSpan = _buildTextSpan(context);
StrutStyle strutStyle = StrutStyle strutStyle =
StrutStyle.fromTextStyle(textSpan.style, forceStrutHeight: true); StrutStyle.fromTextStyle(textSpan.style!, forceStrutHeight: true);
final textAlign = _getTextAlign(); final textAlign = _getTextAlign();
RichText child = RichText( RichText child = RichText(
text: TextSpan(children: [textSpan]), text: TextSpan(children: [textSpan]),
@ -56,7 +57,7 @@ class TextLine extends StatelessWidget {
); );
return RichTextProxy( return RichTextProxy(
child, child,
textSpan.style, textSpan.style!,
textAlign, textAlign,
textDirection, textDirection,
1.0, 1.0,
@ -88,28 +89,28 @@ class TextLine extends StatelessWidget {
TextStyle textStyle = TextStyle(); TextStyle textStyle = TextStyle();
if (line.style.containsKey(Attribute.placeholder.key)) { if (line.style.containsKey(Attribute.placeholder.key!)) {
textStyle = defaultStyles.placeHolder.style; textStyle = defaultStyles.placeHolder!.style;
return TextSpan(children: children, style: textStyle); return TextSpan(children: children, style: textStyle);
} }
Attribute header = line.style.attributes[Attribute.header.key]; Attribute? header = line.style.attributes[Attribute.header.key!];
Map<Attribute, TextStyle> m = { Map<Attribute, TextStyle> m = {
Attribute.h1: defaultStyles.h1.style, Attribute.h1: defaultStyles.h1!.style,
Attribute.h2: defaultStyles.h2.style, Attribute.h2: defaultStyles.h2!.style,
Attribute.h3: defaultStyles.h3.style, Attribute.h3: defaultStyles.h3!.style,
}; };
textStyle = textStyle.merge(m[header] ?? defaultStyles.paragraph.style); textStyle = textStyle.merge(m[header] ?? defaultStyles.paragraph!.style);
Attribute block = line.style.getBlockExceptHeader(); Attribute? block = line.style.getBlockExceptHeader();
TextStyle toMerge; TextStyle? toMerge;
if (block == Attribute.blockQuote) { if (block == Attribute.blockQuote) {
toMerge = defaultStyles.quote.style; toMerge = defaultStyles.quote!.style;
} else if (block == Attribute.codeBlock) { } else if (block == Attribute.codeBlock) {
toMerge = defaultStyles.code.style; toMerge = defaultStyles.code!.style;
} else if (block != null) { } else if (block != null) {
toMerge = defaultStyles.lists.style; toMerge = defaultStyles.lists!.style;
} }
textStyle = textStyle.merge(toMerge); textStyle = textStyle.merge(toMerge);
@ -123,11 +124,11 @@ class TextLine extends StatelessWidget {
TextStyle res = TextStyle(); TextStyle res = TextStyle();
Map<String, TextStyle> m = { Map<String, TextStyle> m = {
Attribute.bold.key: defaultStyles.bold, Attribute.bold.key!: defaultStyles.bold!,
Attribute.italic.key: defaultStyles.italic, Attribute.italic.key!: defaultStyles.italic!,
Attribute.link.key: defaultStyles.link, Attribute.link.key!: defaultStyles.link!,
Attribute.underline.key: defaultStyles.underline, Attribute.underline.key!: defaultStyles.underline!,
Attribute.strikeThrough.key: defaultStyles.strikeThrough, Attribute.strikeThrough.key!: defaultStyles.strikeThrough!,
}; };
m.forEach((k, s) { m.forEach((k, s) {
if (style.values.any((v) => v.key == k)) { if (style.values.any((v) => v.key == k)) {
@ -135,12 +136,12 @@ class TextLine extends StatelessWidget {
} }
}); });
Attribute font = textNode.style.attributes[Attribute.font.key]; Attribute? font = textNode.style.attributes[Attribute.font.key];
if (font != null && font.value != null) { if (font != null && font.value != null) {
res = res.merge(TextStyle(fontFamily: font.value)); res = res.merge(TextStyle(fontFamily: font.value));
} }
Attribute size = textNode.style.attributes[Attribute.size.key]; Attribute? size = textNode.style.attributes[Attribute.size.key];
if (size != null && size.value != null) { if (size != null && size.value != null) {
switch (size.value) { switch (size.value) {
case 'small': case 'small':
@ -153,7 +154,7 @@ class TextLine extends StatelessWidget {
res = res.merge(defaultStyles.sizeHuge); res = res.merge(defaultStyles.sizeHuge);
break; break;
default: default:
double fontSize = double.tryParse(size.value); double? fontSize = double.tryParse(size.value);
if (fontSize != null) { if (fontSize != null) {
res = res.merge(TextStyle(fontSize: fontSize)); res = res.merge(TextStyle(fontSize: fontSize));
} else { } else {
@ -162,13 +163,13 @@ class TextLine extends StatelessWidget {
} }
} }
Attribute color = textNode.style.attributes[Attribute.color.key]; Attribute? color = textNode.style.attributes[Attribute.color.key];
if (color != null && color.value != null) { if (color != null && color.value != null) {
final textColor = stringToColor(color.value); final textColor = stringToColor(color.value);
res = res.merge(new TextStyle(color: textColor)); res = res.merge(new TextStyle(color: textColor));
} }
Attribute background = textNode.style.attributes[Attribute.background.key]; Attribute? background = textNode.style.attributes[Attribute.background.key];
if (background != null && background.value != null) { if (background != null && background.value != null) {
final backgroundColor = stringToColor(background.value); final backgroundColor = stringToColor(background.value);
res = res.merge(new TextStyle(backgroundColor: backgroundColor)); res = res.merge(new TextStyle(backgroundColor: backgroundColor));
@ -180,10 +181,10 @@ class TextLine extends StatelessWidget {
TextStyle _merge(TextStyle a, TextStyle b) { TextStyle _merge(TextStyle a, TextStyle b) {
final decorations = <TextDecoration>[]; final decorations = <TextDecoration>[];
if (a.decoration != null) { if (a.decoration != null) {
decorations.add(a.decoration); decorations.add(a.decoration!);
} }
if (b.decoration != null) { if (b.decoration != null) {
decorations.add(b.decoration); decorations.add(b.decoration!);
} }
return a.merge(b).apply(decoration: TextDecoration.combine(decorations)); return a.merge(b).apply(decoration: TextDecoration.combine(decorations));
} }
@ -191,8 +192,8 @@ class TextLine extends StatelessWidget {
class EditableTextLine extends RenderObjectWidget { class EditableTextLine extends RenderObjectWidget {
final Line line; final Line line;
final Widget leading; final Widget? leading;
final Widget body; final Widget? body;
final double indentWidth; final double indentWidth;
final Tuple2 verticalSpacing; final Tuple2 verticalSpacing;
final TextDirection textDirection; final TextDirection textDirection;
@ -215,14 +216,7 @@ class EditableTextLine extends RenderObjectWidget {
this.enableInteractiveSelection, this.enableInteractiveSelection,
this.hasFocus, this.hasFocus,
this.devicePixelRatio, this.devicePixelRatio,
this.cursorCont) this.cursorCont);
: assert(line != null),
assert(indentWidth != null),
assert(textSelection != null),
assert(color != null),
assert(enableInteractiveSelection != null),
assert(hasFocus != null),
assert(cursorCont != null);
@override @override
RenderObjectElement createElement() { RenderObjectElement createElement() {
@ -268,21 +262,21 @@ class EditableTextLine extends RenderObjectWidget {
enum TextLineSlot { LEADING, BODY } enum TextLineSlot { LEADING, BODY }
class RenderEditableTextLine extends RenderEditableBox { class RenderEditableTextLine extends RenderEditableBox {
RenderBox _leading; RenderBox? _leading;
RenderContentProxyBox _body; RenderContentProxyBox? _body;
Line line; Line line;
TextDirection textDirection; TextDirection? textDirection;
TextSelection textSelection; TextSelection? textSelection;
Color color; Color color;
bool enableInteractiveSelection; bool? enableInteractiveSelection;
bool hasFocus = false; bool hasFocus = false;
double devicePixelRatio; double devicePixelRatio;
EdgeInsetsGeometry padding; EdgeInsetsGeometry padding;
CursorCont cursorCont; CursorCont cursorCont;
EdgeInsets _resolvedPadding; EdgeInsets? _resolvedPadding;
bool _containsCursor; bool? _containsCursor;
List<TextBox> _selectedRects; List<TextBox>? _selectedRects;
Rect _caretPrototype; Rect? _caretPrototype;
final Map<TextLineSlot, RenderBox> children = <TextLineSlot, RenderBox>{}; final Map<TextLineSlot, RenderBox> children = <TextLineSlot, RenderBox>{};
RenderEditableTextLine( RenderEditableTextLine(
@ -295,25 +289,18 @@ class RenderEditableTextLine extends RenderEditableBox {
this.padding, this.padding,
this.color, this.color,
this.cursorCont) this.cursorCont)
: assert(line != null), : assert(padding.isNonNegative);
assert(padding != null),
assert(padding.isNonNegative),
assert(devicePixelRatio != null),
assert(hasFocus != null),
assert(color != null),
assert(cursorCont != null);
Iterable<RenderBox> get _children sync* { Iterable<RenderBox> get _children sync* {
if (_leading != null) { if (_leading != null) {
yield _leading; yield _leading!;
} }
if (_body != null) { if (_body != null) {
yield _body; yield _body!;
} }
} }
setCursorCont(CursorCont c) { setCursorCont(CursorCont c) {
assert(c != null);
if (cursorCont == c) { if (cursorCont == c) {
return; return;
} }
@ -383,7 +370,6 @@ class RenderEditableTextLine extends RenderEditableBox {
} }
setLine(Line l) { setLine(Line l) {
assert(l != null);
if (line == l) { if (line == l) {
return; return;
} }
@ -393,7 +379,6 @@ class RenderEditableTextLine extends RenderEditableBox {
} }
setPadding(EdgeInsetsGeometry p) { setPadding(EdgeInsetsGeometry p) {
assert(p != null);
assert(p.isNonNegative); assert(p.isNonNegative);
if (padding == p) { if (padding == p) {
return; return;
@ -408,20 +393,21 @@ class RenderEditableTextLine extends RenderEditableBox {
} }
setBody(RenderContentProxyBox b) { setBody(RenderContentProxyBox b) {
_body = _updateChild(_body, b, TextLineSlot.BODY); _body = _updateChild(_body, b, TextLineSlot.BODY) as RenderContentProxyBox;
} }
bool containsTextSelection() { bool containsTextSelection() {
return line.getDocumentOffset() <= textSelection.end && return line.getDocumentOffset() <= textSelection!.end &&
textSelection.start <= line.getDocumentOffset() + line.length - 1; textSelection!.start <= line.getDocumentOffset() + line.length - 1;
} }
bool containsCursor() { bool containsCursor() {
return _containsCursor ??= textSelection.isCollapsed && return _containsCursor ??= textSelection!.isCollapsed &&
line.containsOffset(textSelection.baseOffset); line.containsOffset(textSelection!.baseOffset);
} }
RenderBox _updateChild(RenderBox old, RenderBox newChild, TextLineSlot slot) { RenderBox? _updateChild(
RenderBox? old, RenderBox? newChild, TextLineSlot slot) {
if (old != null) { if (old != null) {
dropChild(old); dropChild(old);
children.remove(slot); children.remove(slot);
@ -434,8 +420,8 @@ class RenderEditableTextLine extends RenderEditableBox {
} }
List<TextBox> _getBoxes(TextSelection textSelection) { List<TextBox> _getBoxes(TextSelection textSelection) {
BoxParentData parentData = _body.parentData as BoxParentData; BoxParentData parentData = _body!.parentData as BoxParentData;
return _body.getBoxesForSelection(textSelection).map((box) { return _body!.getBoxesForSelection(textSelection).map((box) {
return TextBox.fromLTRBD( return TextBox.fromLTRBD(
box.left + parentData.offset.dx, box.left + parentData.offset.dx,
box.top + parentData.offset.dy, box.top + parentData.offset.dy,
@ -451,7 +437,7 @@ class RenderEditableTextLine extends RenderEditableBox {
return; return;
} }
_resolvedPadding = padding.resolve(textDirection); _resolvedPadding = padding.resolve(textDirection);
assert(_resolvedPadding.isNonNegative); assert(_resolvedPadding!.isNonNegative);
} }
@override @override
@ -498,26 +484,26 @@ class RenderEditableTextLine extends RenderEditableBox {
@override @override
Offset getOffsetForCaret(TextPosition position) { Offset getOffsetForCaret(TextPosition position) {
return _body.getOffsetForCaret(position, _caretPrototype) + return _body!.getOffsetForCaret(position, _caretPrototype!) +
(_body.parentData as BoxParentData).offset; (_body!.parentData as BoxParentData).offset;
} }
@override @override
TextPosition getPositionAbove(TextPosition position) { TextPosition? getPositionAbove(TextPosition position) {
return _getPosition(position, -0.5); return _getPosition(position, -0.5);
} }
@override @override
TextPosition getPositionBelow(TextPosition position) { TextPosition? getPositionBelow(TextPosition position) {
return _getPosition(position, 1.5); return _getPosition(position, 1.5);
} }
TextPosition _getPosition(TextPosition textPosition, double dyScale) { TextPosition? _getPosition(TextPosition textPosition, double dyScale) {
assert(textPosition.offset < line.length); assert(textPosition.offset < line.length);
Offset offset = getOffsetForCaret(textPosition) Offset offset = getOffsetForCaret(textPosition)
.translate(0, dyScale * preferredLineHeight(textPosition)); .translate(0, dyScale * preferredLineHeight(textPosition));
if (_body.size if (_body!.size
.contains(offset - (_body.parentData as BoxParentData).offset)) { .contains(offset - (_body!.parentData as BoxParentData).offset)) {
return getPositionForOffset(offset); return getPositionForOffset(offset);
} }
return null; return null;
@ -525,18 +511,18 @@ class RenderEditableTextLine extends RenderEditableBox {
@override @override
TextPosition getPositionForOffset(Offset offset) { TextPosition getPositionForOffset(Offset offset) {
return _body.getPositionForOffset( return _body!.getPositionForOffset(
offset - (_body.parentData as BoxParentData).offset); offset - (_body!.parentData as BoxParentData).offset);
} }
@override @override
TextRange getWordBoundary(TextPosition position) { TextRange getWordBoundary(TextPosition position) {
return _body.getWordBoundary(position); return _body!.getWordBoundary(position);
} }
@override @override
double preferredLineHeight(TextPosition position) { double preferredLineHeight(TextPosition position) {
return _body.getPreferredLineHeight(); return _body!.getPreferredLineHeight();
} }
@override @override
@ -550,7 +536,6 @@ class RenderEditableTextLine extends RenderEditableBox {
cursorCont.style.height ?? preferredLineHeight(TextPosition(offset: 0)); cursorCont.style.height ?? preferredLineHeight(TextPosition(offset: 0));
_computeCaretPrototype() { _computeCaretPrototype() {
assert(defaultTargetPlatform != null);
switch (defaultTargetPlatform) { switch (defaultTargetPlatform) {
case TargetPlatform.iOS: case TargetPlatform.iOS:
case TargetPlatform.macOS: case TargetPlatform.macOS:
@ -606,14 +591,14 @@ class RenderEditableTextLine extends RenderEditableBox {
@override @override
List<DiagnosticsNode> debugDescribeChildren() { List<DiagnosticsNode> debugDescribeChildren() {
var value = <DiagnosticsNode>[]; var value = <DiagnosticsNode>[];
void add(RenderBox child, String name) { void add(RenderBox? child, String name) {
if (child != null) { if (child != null) {
value.add(child.toDiagnosticsNode(name: name)); value.add(child.toDiagnosticsNode(name: name));
} }
} }
add(_leading, 'leading'); add(_leading!, 'leading');
add(_body, 'body'); add(_body!, 'body');
return value; return value;
} }
@ -623,38 +608,40 @@ class RenderEditableTextLine extends RenderEditableBox {
@override @override
double computeMinIntrinsicWidth(double height) { double computeMinIntrinsicWidth(double height) {
_resolvePadding(); _resolvePadding();
double horizontalPadding = _resolvedPadding.left + _resolvedPadding.right; double horizontalPadding = _resolvedPadding!.left + _resolvedPadding!.right;
double verticalPadding = _resolvedPadding.top + _resolvedPadding.bottom; double verticalPadding = _resolvedPadding!.top + _resolvedPadding!.bottom;
int leadingWidth = _leading == null int leadingWidth = _leading == null
? 0 ? 0
: _leading.getMinIntrinsicWidth(height - verticalPadding); : (_leading!.getMinIntrinsicWidth(height - verticalPadding) as int);
int bodyWidth = _body == null int bodyWidth = _body == null
? 0 ? 0
: _body.getMinIntrinsicWidth(math.max(0.0, height - verticalPadding)); : (_body!.getMinIntrinsicWidth(math.max(0.0, height - verticalPadding))
as int);
return horizontalPadding + leadingWidth + bodyWidth; return horizontalPadding + leadingWidth + bodyWidth;
} }
@override @override
double computeMaxIntrinsicWidth(double height) { double computeMaxIntrinsicWidth(double height) {
_resolvePadding(); _resolvePadding();
double horizontalPadding = _resolvedPadding.left + _resolvedPadding.right; double horizontalPadding = _resolvedPadding!.left + _resolvedPadding!.right;
double verticalPadding = _resolvedPadding.top + _resolvedPadding.bottom; double verticalPadding = _resolvedPadding!.top + _resolvedPadding!.bottom;
int leadingWidth = _leading == null int leadingWidth = _leading == null
? 0 ? 0
: _leading.getMaxIntrinsicWidth(height - verticalPadding); : (_leading!.getMaxIntrinsicWidth(height - verticalPadding) as int);
int bodyWidth = _body == null int bodyWidth = _body == null
? 0 ? 0
: _body.getMaxIntrinsicWidth(math.max(0.0, height - verticalPadding)); : (_body!.getMaxIntrinsicWidth(math.max(0.0, height - verticalPadding))
as int);
return horizontalPadding + leadingWidth + bodyWidth; return horizontalPadding + leadingWidth + bodyWidth;
} }
@override @override
double computeMinIntrinsicHeight(double width) { double computeMinIntrinsicHeight(double width) {
_resolvePadding(); _resolvePadding();
double horizontalPadding = _resolvedPadding.left + _resolvedPadding.right; double horizontalPadding = _resolvedPadding!.left + _resolvedPadding!.right;
double verticalPadding = _resolvedPadding.top + _resolvedPadding.bottom; double verticalPadding = _resolvedPadding!.top + _resolvedPadding!.bottom;
if (_body != null) { if (_body != null) {
return _body return _body!
.getMinIntrinsicHeight(math.max(0.0, width - horizontalPadding)) + .getMinIntrinsicHeight(math.max(0.0, width - horizontalPadding)) +
verticalPadding; verticalPadding;
} }
@ -664,10 +651,10 @@ class RenderEditableTextLine extends RenderEditableBox {
@override @override
double computeMaxIntrinsicHeight(double width) { double computeMaxIntrinsicHeight(double width) {
_resolvePadding(); _resolvePadding();
double horizontalPadding = _resolvedPadding.left + _resolvedPadding.right; double horizontalPadding = _resolvedPadding!.left + _resolvedPadding!.right;
double verticalPadding = _resolvedPadding.top + _resolvedPadding.bottom; double verticalPadding = _resolvedPadding!.top + _resolvedPadding!.bottom;
if (_body != null) { if (_body != null) {
return _body return _body!
.getMaxIntrinsicHeight(math.max(0.0, width - horizontalPadding)) + .getMaxIntrinsicHeight(math.max(0.0, width - horizontalPadding)) +
verticalPadding; verticalPadding;
} }
@ -677,7 +664,8 @@ class RenderEditableTextLine extends RenderEditableBox {
@override @override
double computeDistanceToActualBaseline(TextBaseline baseline) { double computeDistanceToActualBaseline(TextBaseline baseline) {
_resolvePadding(); _resolvePadding();
return _body.getDistanceToActualBaseline(baseline) + _resolvedPadding.top; return _body!.getDistanceToActualBaseline(baseline)! +
_resolvedPadding!.top;
} }
@override @override
@ -690,43 +678,44 @@ class RenderEditableTextLine extends RenderEditableBox {
if (_body == null && _leading == null) { if (_body == null && _leading == null) {
size = constraints.constrain(Size( size = constraints.constrain(Size(
_resolvedPadding.left + _resolvedPadding.right, _resolvedPadding!.left + _resolvedPadding!.right,
_resolvedPadding.top + _resolvedPadding.bottom, _resolvedPadding!.top + _resolvedPadding!.bottom,
)); ));
return; return;
} }
final innerConstraints = constraints.deflate(_resolvedPadding); final innerConstraints = constraints.deflate(_resolvedPadding!);
final indentWidth = textDirection == TextDirection.ltr final indentWidth = textDirection == TextDirection.ltr
? _resolvedPadding.left ? _resolvedPadding!.left
: _resolvedPadding.right; : _resolvedPadding!.right;
_body.layout(innerConstraints, parentUsesSize: true); _body!.layout(innerConstraints, parentUsesSize: true);
final bodyParentData = _body.parentData as BoxParentData; final bodyParentData = _body!.parentData as BoxParentData;
bodyParentData.offset = Offset(_resolvedPadding.left, _resolvedPadding.top); bodyParentData.offset =
Offset(_resolvedPadding!.left, _resolvedPadding!.top);
if (_leading != null) { if (_leading != null) {
final leadingConstraints = innerConstraints.copyWith( final leadingConstraints = innerConstraints.copyWith(
minWidth: indentWidth, minWidth: indentWidth,
maxWidth: indentWidth, maxWidth: indentWidth,
maxHeight: _body.size.height); maxHeight: _body!.size.height);
_leading.layout(leadingConstraints, parentUsesSize: true); _leading!.layout(leadingConstraints, parentUsesSize: true);
final parentData = _leading.parentData as BoxParentData; final parentData = _leading!.parentData as BoxParentData;
parentData.offset = Offset(0.0, _resolvedPadding.top); parentData.offset = Offset(0.0, _resolvedPadding!.top);
} }
size = constraints.constrain(Size( size = constraints.constrain(Size(
_resolvedPadding.left + _body.size.width + _resolvedPadding.right, _resolvedPadding!.left + _body!.size.width + _resolvedPadding!.right,
_resolvedPadding.top + _body.size.height + _resolvedPadding.bottom, _resolvedPadding!.top + _body!.size.height + _resolvedPadding!.bottom,
)); ));
_computeCaretPrototype(); _computeCaretPrototype();
} }
CursorPainter get _cursorPainter => CursorPainter( CursorPainter get _cursorPainter => CursorPainter(
_body, _body!,
cursorCont.style, cursorCont.style,
_caretPrototype, _caretPrototype!,
cursorCont.cursorColor.value, cursorCont.cursorColor.value,
devicePixelRatio, devicePixelRatio,
); );
@ -734,19 +723,19 @@ class RenderEditableTextLine extends RenderEditableBox {
@override @override
paint(PaintingContext context, Offset offset) { paint(PaintingContext context, Offset offset) {
if (_leading != null) { if (_leading != null) {
final parentData = _leading.parentData as BoxParentData; final parentData = _leading!.parentData as BoxParentData;
final effectiveOffset = offset + parentData.offset; final effectiveOffset = offset + parentData.offset;
context.paintChild(_leading, effectiveOffset); context.paintChild(_leading!, effectiveOffset);
} }
if (_body != null) { if (_body != null) {
final parentData = _body.parentData as BoxParentData; final parentData = _body!.parentData as BoxParentData;
final effectiveOffset = offset + parentData.offset; final effectiveOffset = offset + parentData.offset;
if ((enableInteractiveSelection ?? true) && if ((enableInteractiveSelection ?? true) &&
line.getDocumentOffset() <= textSelection.end && line.getDocumentOffset() <= textSelection!.end &&
textSelection.start <= line.getDocumentOffset() + line.length - 1) { textSelection!.start <= line.getDocumentOffset() + line.length - 1) {
final local = localSelection(line, textSelection, false); final local = localSelection(line, textSelection!, false);
_selectedRects ??= _body.getBoxesForSelection( _selectedRects ??= _body!.getBoxesForSelection(
local, local,
); );
_paintSelection(context, effectiveOffset); _paintSelection(context, effectiveOffset);
@ -759,7 +748,7 @@ class RenderEditableTextLine extends RenderEditableBox {
_paintCursor(context, effectiveOffset); _paintCursor(context, effectiveOffset);
} }
context.paintChild(_body, effectiveOffset); context.paintChild(_body!, effectiveOffset);
if (hasFocus && if (hasFocus &&
cursorCont.show.value && cursorCont.show.value &&
@ -773,15 +762,15 @@ class RenderEditableTextLine extends RenderEditableBox {
_paintSelection(PaintingContext context, Offset effectiveOffset) { _paintSelection(PaintingContext context, Offset effectiveOffset) {
assert(_selectedRects != null); assert(_selectedRects != null);
final paint = Paint()..color = color; final paint = Paint()..color = color;
for (final box in _selectedRects) { for (final box in _selectedRects!) {
context.canvas.drawRect(box.toRect().shift(effectiveOffset), paint); context.canvas.drawRect(box.toRect().shift(effectiveOffset), paint);
} }
} }
_paintCursor(PaintingContext context, Offset effectiveOffset) { _paintCursor(PaintingContext context, Offset effectiveOffset) {
final position = TextPosition( final position = TextPosition(
offset: textSelection.extentOffset - line.getDocumentOffset(), offset: textSelection!.extentOffset - line.getDocumentOffset(),
affinity: textSelection.base.affinity, affinity: textSelection!.base.affinity,
); );
_cursorPainter.paint(context.canvas, effectiveOffset, position); _cursorPainter.paint(context.canvas, effectiveOffset, position);
} }
@ -814,7 +803,7 @@ class _TextLineElement extends RenderObjectElement {
} }
@override @override
mount(Element parent, dynamic newSlot) { mount(Element? parent, dynamic newSlot) {
super.mount(parent, newSlot); super.mount(parent, newSlot);
_mountChild(widget.leading, TextLineSlot.LEADING); _mountChild(widget.leading, TextLineSlot.LEADING);
_mountChild(widget.body, TextLineSlot.BODY); _mountChild(widget.body, TextLineSlot.BODY);
@ -848,9 +837,9 @@ class _TextLineElement extends RenderObjectElement {
throw UnimplementedError(); throw UnimplementedError();
} }
_mountChild(Widget widget, TextLineSlot slot) { _mountChild(Widget? widget, TextLineSlot slot) {
Element oldChild = _slotToChildren[slot]; Element? oldChild = _slotToChildren[slot];
Element newChild = updateChild(oldChild, widget, slot); Element? newChild = updateChild(oldChild, widget, slot);
if (oldChild != null) { if (oldChild != null) {
_slotToChildren.remove(slot); _slotToChildren.remove(slot);
} }
@ -859,22 +848,22 @@ class _TextLineElement extends RenderObjectElement {
} }
} }
_updateRenderObject(RenderObject child, TextLineSlot slot) { _updateRenderObject(RenderObject? child, TextLineSlot slot) {
switch (slot) { switch (slot) {
case TextLineSlot.LEADING: case TextLineSlot.LEADING:
renderObject.setLeading(child as RenderBox); renderObject.setLeading(child as RenderBox);
break; break;
case TextLineSlot.BODY: case TextLineSlot.BODY:
renderObject.setBody(child as RenderBox); renderObject.setBody(child as RenderContentProxyBox);
break; break;
default: default:
throw UnimplementedError(); throw UnimplementedError();
} }
} }
_updateChild(Widget widget, TextLineSlot slot) { _updateChild(Widget? widget, TextLineSlot slot) {
Element oldChild = _slotToChildren[slot]; Element? oldChild = _slotToChildren[slot];
Element newChild = updateChild(oldChild, widget, slot); Element? newChild = updateChild(oldChild, widget, slot);
if (oldChild != null) { if (oldChild != null) {
_slotToChildren.remove(slot); _slotToChildren.remove(slot);
} }

@ -27,19 +27,19 @@ class EditorTextSelectionOverlay {
TextEditingValue value; TextEditingValue value;
bool handlesVisible = false; bool handlesVisible = false;
final BuildContext context; final BuildContext context;
final Widget debugRequiredFor; final Widget? debugRequiredFor;
final LayerLink toolbarLayerLink; final LayerLink? toolbarLayerLink;
final LayerLink startHandleLayerLink; final LayerLink? startHandleLayerLink;
final LayerLink endHandleLayerLink; final LayerLink? endHandleLayerLink;
final RenderEditor renderObject; final RenderEditor? renderObject;
final TextSelectionControls selectionCtrls; final TextSelectionControls? selectionCtrls;
final TextSelectionDelegate selectionDelegate; final TextSelectionDelegate? selectionDelegate;
final DragStartBehavior dragStartBehavior; final DragStartBehavior? dragStartBehavior;
final VoidCallback onSelectionHandleTapped; final VoidCallback? onSelectionHandleTapped;
final ClipboardStatusNotifier clipboardStatus; final ClipboardStatusNotifier? clipboardStatus;
AnimationController _toolbarController; AnimationController? _toolbarController;
List<OverlayEntry> _handles; List<OverlayEntry>? _handles;
OverlayEntry toolbar; OverlayEntry? toolbar;
EditorTextSelectionOverlay( EditorTextSelectionOverlay(
this.value, this.value,
@ -54,31 +54,24 @@ class EditorTextSelectionOverlay {
this.selectionDelegate, this.selectionDelegate,
this.dragStartBehavior, this.dragStartBehavior,
this.onSelectionHandleTapped, this.onSelectionHandleTapped,
this.clipboardStatus) this.clipboardStatus) {
: assert(value != null), OverlayState overlay = Overlay.of(context, rootOverlay: true)!;
assert(context != null),
assert(handlesVisible != null) {
OverlayState overlay = Overlay.of(context, rootOverlay: true);
assert(
overlay != null,
);
_toolbarController = AnimationController( _toolbarController = AnimationController(
duration: Duration(milliseconds: 150), vsync: overlay); duration: Duration(milliseconds: 150), vsync: overlay);
} }
TextSelection get _selection => value.selection; TextSelection get _selection => value.selection;
Animation<double> get _toolbarOpacity => _toolbarController.view; Animation<double> get _toolbarOpacity => _toolbarController!.view;
setHandlesVisible(bool visible) { setHandlesVisible(bool visible) {
assert(visible != null);
if (handlesVisible == visible) { if (handlesVisible == visible) {
return; return;
} }
handlesVisible = visible; handlesVisible = visible;
if (SchedulerBinding.instance.schedulerPhase == if (SchedulerBinding.instance!.schedulerPhase ==
SchedulerPhase.persistentCallbacks) { SchedulerPhase.persistentCallbacks) {
SchedulerBinding.instance.addPostFrameCallback(markNeedsBuild); SchedulerBinding.instance!.addPostFrameCallback(markNeedsBuild);
} else { } else {
markNeedsBuild(); markNeedsBuild();
} }
@ -88,24 +81,24 @@ class EditorTextSelectionOverlay {
if (_handles == null) { if (_handles == null) {
return; return;
} }
_handles[0].remove(); _handles![0].remove();
_handles[1].remove(); _handles![1].remove();
_handles = null; _handles = null;
} }
hideToolbar() { hideToolbar() {
assert(toolbar != null); assert(toolbar != null);
_toolbarController.stop(); _toolbarController!.stop();
toolbar.remove(); toolbar!.remove();
toolbar = null; toolbar = null;
} }
showToolbar() { showToolbar() {
assert(toolbar == null); assert(toolbar == null);
toolbar = OverlayEntry(builder: _buildToolbar); toolbar = OverlayEntry(builder: _buildToolbar);
Overlay.of(context, rootOverlay: true, debugRequiredFor: debugRequiredFor) Overlay.of(context, rootOverlay: true, debugRequiredFor: debugRequiredFor)!
.insert(toolbar); .insert(toolbar!);
_toolbarController.forward(from: 0.0); _toolbarController!.forward(from: 0.0);
} }
Widget _buildHandle( Widget _buildHandle(
@ -122,13 +115,13 @@ class EditorTextSelectionOverlay {
_handleSelectionHandleChanged(newSelection, position); _handleSelectionHandleChanged(newSelection, position);
}, },
onSelectionHandleTapped: onSelectionHandleTapped, onSelectionHandleTapped: onSelectionHandleTapped,
startHandleLayerLink: startHandleLayerLink, startHandleLayerLink: startHandleLayerLink!,
endHandleLayerLink: endHandleLayerLink, endHandleLayerLink: endHandleLayerLink!,
renderObject: renderObject, renderObject: renderObject!,
selection: _selection, selection: _selection,
selectionControls: selectionCtrls, selectionControls: selectionCtrls!,
position: position, position: position,
dragStartBehavior: dragStartBehavior, dragStartBehavior: dragStartBehavior!,
)); ));
} }
@ -137,9 +130,9 @@ class EditorTextSelectionOverlay {
return; return;
} }
value = newValue; value = newValue;
if (SchedulerBinding.instance.schedulerPhase == if (SchedulerBinding.instance!.schedulerPhase ==
SchedulerPhase.persistentCallbacks) { SchedulerPhase.persistentCallbacks) {
SchedulerBinding.instance.addPostFrameCallback(markNeedsBuild); SchedulerBinding.instance!.addPostFrameCallback(markNeedsBuild);
} else { } else {
markNeedsBuild(); markNeedsBuild();
} }
@ -158,9 +151,9 @@ class EditorTextSelectionOverlay {
default: default:
throw ('Invalid position'); throw ('Invalid position');
} }
selectionDelegate.textEditingValue = selectionDelegate!.textEditingValue =
value.copyWith(selection: newSelection, composing: TextRange.empty); value.copyWith(selection: newSelection, composing: TextRange.empty);
selectionDelegate.bringIntoView(textPosition); selectionDelegate!.bringIntoView(textPosition);
} }
Widget _buildToolbar(BuildContext context) { Widget _buildToolbar(BuildContext context) {
@ -169,16 +162,16 @@ class EditorTextSelectionOverlay {
} }
List<TextSelectionPoint> endpoints = List<TextSelectionPoint> endpoints =
renderObject.getEndpointsForSelection(_selection); renderObject!.getEndpointsForSelection(_selection);
Rect editingRegion = Rect.fromPoints( Rect editingRegion = Rect.fromPoints(
renderObject.localToGlobal(Offset.zero), renderObject!.localToGlobal(Offset.zero),
renderObject.localToGlobal(renderObject.size.bottomRight(Offset.zero)), renderObject!.localToGlobal(renderObject!.size.bottomRight(Offset.zero)),
); );
double baseLineHeight = renderObject.preferredLineHeight(_selection.base); double baseLineHeight = renderObject!.preferredLineHeight(_selection.base);
double extentLineHeight = double extentLineHeight =
renderObject.preferredLineHeight(_selection.extent); renderObject!.preferredLineHeight(_selection.extent);
double smallestLineHeight = math.min(baseLineHeight, extentLineHeight); double smallestLineHeight = math.min(baseLineHeight, extentLineHeight);
bool isMultiline = endpoints.last.point.dy - endpoints.first.point.dy > bool isMultiline = endpoints.last.point.dy - endpoints.first.point.dy >
smallestLineHeight / 2; smallestLineHeight / 2;
@ -195,34 +188,34 @@ class EditorTextSelectionOverlay {
return FadeTransition( return FadeTransition(
opacity: _toolbarOpacity, opacity: _toolbarOpacity,
child: CompositedTransformFollower( child: CompositedTransformFollower(
link: toolbarLayerLink, link: toolbarLayerLink!,
showWhenUnlinked: false, showWhenUnlinked: false,
offset: -editingRegion.topLeft, offset: -editingRegion.topLeft,
child: selectionCtrls.buildToolbar( child: selectionCtrls!.buildToolbar(
context, context,
editingRegion, editingRegion,
baseLineHeight, baseLineHeight,
midpoint, midpoint,
endpoints, endpoints,
selectionDelegate, selectionDelegate!,
clipboardStatus, clipboardStatus!,
Offset(0, 0)), Offset(0, 0)),
), ),
); );
} }
markNeedsBuild([Duration duration]) { markNeedsBuild([Duration? duration]) {
if (_handles != null) { if (_handles != null) {
_handles[0].markNeedsBuild(); _handles![0].markNeedsBuild();
_handles[1].markNeedsBuild(); _handles![1].markNeedsBuild();
} }
toolbar?.markNeedsBuild(); toolbar?.markNeedsBuild();
} }
hide() { hide() {
if (_handles != null) { if (_handles != null) {
_handles[0].remove(); _handles![0].remove();
_handles[1].remove(); _handles![1].remove();
_handles = null; _handles = null;
} }
if (toolbar != null) { if (toolbar != null) {
@ -232,7 +225,7 @@ class EditorTextSelectionOverlay {
dispose() { dispose() {
hide(); hide();
_toolbarController.dispose(); _toolbarController!.dispose();
} }
void showHandles() { void showHandles() {
@ -246,22 +239,22 @@ class EditorTextSelectionOverlay {
_buildHandle(context, _TextSelectionHandlePosition.END)), _buildHandle(context, _TextSelectionHandlePosition.END)),
]; ];
Overlay.of(context, rootOverlay: true, debugRequiredFor: debugRequiredFor) Overlay.of(context, rootOverlay: true, debugRequiredFor: debugRequiredFor)!
.insertAll(_handles); .insertAll(_handles!);
} }
} }
class _TextSelectionHandleOverlay extends StatefulWidget { class _TextSelectionHandleOverlay extends StatefulWidget {
const _TextSelectionHandleOverlay({ const _TextSelectionHandleOverlay({
Key key, Key? key,
@required this.selection, required this.selection,
@required this.position, required this.position,
@required this.startHandleLayerLink, required this.startHandleLayerLink,
@required this.endHandleLayerLink, required this.endHandleLayerLink,
@required this.renderObject, required this.renderObject,
@required this.onSelectionHandleChanged, required this.onSelectionHandleChanged,
@required this.onSelectionHandleTapped, required this.onSelectionHandleTapped,
@required this.selectionControls, required this.selectionControls,
this.dragStartBehavior = DragStartBehavior.start, this.dragStartBehavior = DragStartBehavior.start,
}) : super(key: key); }) : super(key: key);
@ -271,7 +264,7 @@ class _TextSelectionHandleOverlay extends StatefulWidget {
final LayerLink endHandleLayerLink; final LayerLink endHandleLayerLink;
final RenderEditor renderObject; final RenderEditor renderObject;
final ValueChanged<TextSelection> onSelectionHandleChanged; final ValueChanged<TextSelection> onSelectionHandleChanged;
final VoidCallback onSelectionHandleTapped; final VoidCallback? onSelectionHandleTapped;
final TextSelectionControls selectionControls; final TextSelectionControls selectionControls;
final DragStartBehavior dragStartBehavior; final DragStartBehavior dragStartBehavior;
@ -286,16 +279,15 @@ class _TextSelectionHandleOverlay extends StatefulWidget {
case _TextSelectionHandlePosition.END: case _TextSelectionHandlePosition.END:
return renderObject.selectionEndInViewport; return renderObject.selectionEndInViewport;
} }
return null;
} }
} }
class _TextSelectionHandleOverlayState class _TextSelectionHandleOverlayState
extends State<_TextSelectionHandleOverlay> extends State<_TextSelectionHandleOverlay>
with SingleTickerProviderStateMixin { with SingleTickerProviderStateMixin {
AnimationController _controller; AnimationController? _controller;
Animation<double> get _opacity => _controller.view; Animation<double> get _opacity => _controller!.view;
@override @override
void initState() { void initState() {
@ -310,9 +302,9 @@ class _TextSelectionHandleOverlayState
_handleVisibilityChanged() { _handleVisibilityChanged() {
if (widget._visibility.value) { if (widget._visibility.value) {
_controller.forward(); _controller!.forward();
} else { } else {
_controller.reverse(); _controller!.reverse();
} }
} }
@ -327,7 +319,7 @@ class _TextSelectionHandleOverlayState
@override @override
void dispose() { void dispose() {
widget._visibility.removeListener(_handleVisibilityChanged); widget._visibility.removeListener(_handleVisibilityChanged);
_controller.dispose(); _controller!.dispose();
super.dispose(); super.dispose();
} }
@ -367,8 +359,9 @@ class _TextSelectionHandleOverlayState
} }
_handleTap() { _handleTap() {
if (widget.onSelectionHandleTapped != null) if (widget.onSelectionHandleTapped != null) {
widget.onSelectionHandleTapped(); widget.onSelectionHandleTapped!();
}
} }
@override @override
@ -465,20 +458,18 @@ class _TextSelectionHandleOverlayState
) { ) {
if (widget.selection.isCollapsed) return TextSelectionHandleType.collapsed; if (widget.selection.isCollapsed) return TextSelectionHandleType.collapsed;
assert(textDirection != null);
switch (textDirection) { switch (textDirection) {
case TextDirection.ltr: case TextDirection.ltr:
return ltrType; return ltrType;
case TextDirection.rtl: case TextDirection.rtl:
return rtlType; return rtlType;
} }
return null;
} }
} }
class EditorTextSelectionGestureDetector extends StatefulWidget { class EditorTextSelectionGestureDetector extends StatefulWidget {
const EditorTextSelectionGestureDetector({ const EditorTextSelectionGestureDetector({
Key key, Key? key,
this.onTapDown, this.onTapDown,
this.onForcePressStart, this.onForcePressStart,
this.onForcePressEnd, this.onForcePressEnd,
@ -492,35 +483,34 @@ class EditorTextSelectionGestureDetector extends StatefulWidget {
this.onDragSelectionUpdate, this.onDragSelectionUpdate,
this.onDragSelectionEnd, this.onDragSelectionEnd,
this.behavior, this.behavior,
@required this.child, required this.child,
}) : assert(child != null), }) : super(key: key);
super(key: key);
final GestureTapDownCallback onTapDown; final GestureTapDownCallback? onTapDown;
final GestureForcePressStartCallback onForcePressStart; final GestureForcePressStartCallback? onForcePressStart;
final GestureForcePressEndCallback onForcePressEnd; final GestureForcePressEndCallback? onForcePressEnd;
final GestureTapUpCallback onSingleTapUp; final GestureTapUpCallback? onSingleTapUp;
final GestureTapCancelCallback onSingleTapCancel; final GestureTapCancelCallback? onSingleTapCancel;
final GestureLongPressStartCallback onSingleLongTapStart; final GestureLongPressStartCallback? onSingleLongTapStart;
final GestureLongPressMoveUpdateCallback onSingleLongTapMoveUpdate; final GestureLongPressMoveUpdateCallback? onSingleLongTapMoveUpdate;
final GestureLongPressEndCallback onSingleLongTapEnd; final GestureLongPressEndCallback? onSingleLongTapEnd;
final GestureTapDownCallback onDoubleTapDown; final GestureTapDownCallback? onDoubleTapDown;
final GestureDragStartCallback onDragSelectionStart; final GestureDragStartCallback? onDragSelectionStart;
final DragSelectionUpdateCallback onDragSelectionUpdate; final DragSelectionUpdateCallback? onDragSelectionUpdate;
final GestureDragEndCallback onDragSelectionEnd; final GestureDragEndCallback? onDragSelectionEnd;
final HitTestBehavior behavior; final HitTestBehavior? behavior;
final Widget child; final Widget child;
@ -531,28 +521,28 @@ class EditorTextSelectionGestureDetector extends StatefulWidget {
class _EditorTextSelectionGestureDetectorState class _EditorTextSelectionGestureDetectorState
extends State<EditorTextSelectionGestureDetector> { extends State<EditorTextSelectionGestureDetector> {
Timer _doubleTapTimer; Timer? _doubleTapTimer;
Offset _lastTapOffset; Offset? _lastTapOffset;
bool _isDoubleTap = false; bool _isDoubleTap = false;
@override @override
void dispose() { void dispose() {
_doubleTapTimer?.cancel(); _doubleTapTimer?.cancel();
_dragUpdateThrottleTimer?.cancel(); _dragUpdateThrottleTimer!.cancel();
super.dispose(); super.dispose();
} }
_handleTapDown(TapDownDetails details) { _handleTapDown(TapDownDetails details) {
if (widget.onTapDown != null) { if (widget.onTapDown != null) {
widget.onTapDown(details); widget.onTapDown!(details);
} }
if (_doubleTapTimer != null && if (_doubleTapTimer != null &&
_isWithinDoubleTapTolerance(details.globalPosition)) { _isWithinDoubleTapTolerance(details.globalPosition)) {
if (widget.onDoubleTapDown != null) { if (widget.onDoubleTapDown != null) {
widget.onDoubleTapDown(details); widget.onDoubleTapDown!(details);
} }
_doubleTapTimer.cancel(); _doubleTapTimer!.cancel();
_doubleTapTimeout(); _doubleTapTimeout();
_isDoubleTap = true; _isDoubleTap = true;
} }
@ -561,7 +551,7 @@ class _EditorTextSelectionGestureDetectorState
_handleTapUp(TapUpDetails details) { _handleTapUp(TapUpDetails details) {
if (!_isDoubleTap) { if (!_isDoubleTap) {
if (widget.onSingleTapUp != null) { if (widget.onSingleTapUp != null) {
widget.onSingleTapUp(details); widget.onSingleTapUp!(details);
} }
_lastTapOffset = details.globalPosition; _lastTapOffset = details.globalPosition;
_doubleTapTimer = Timer(kDoubleTapTimeout, _doubleTapTimeout); _doubleTapTimer = Timer(kDoubleTapTimeout, _doubleTapTimeout);
@ -571,19 +561,19 @@ class _EditorTextSelectionGestureDetectorState
_handleTapCancel() { _handleTapCancel() {
if (widget.onSingleTapCancel != null) { if (widget.onSingleTapCancel != null) {
widget.onSingleTapCancel(); widget.onSingleTapCancel!();
} }
} }
DragStartDetails _lastDragStartDetails; DragStartDetails? _lastDragStartDetails;
DragUpdateDetails _lastDragUpdateDetails; DragUpdateDetails? _lastDragUpdateDetails;
Timer _dragUpdateThrottleTimer; Timer? _dragUpdateThrottleTimer;
_handleDragStart(DragStartDetails details) { _handleDragStart(DragStartDetails details) {
assert(_lastDragStartDetails == null); assert(_lastDragStartDetails == null);
_lastDragStartDetails = details; _lastDragStartDetails = details;
if (widget.onDragSelectionStart != null) { if (widget.onDragSelectionStart != null) {
widget.onDragSelectionStart(details); widget.onDragSelectionStart!(details);
} }
} }
@ -597,8 +587,8 @@ class _EditorTextSelectionGestureDetectorState
assert(_lastDragStartDetails != null); assert(_lastDragStartDetails != null);
assert(_lastDragUpdateDetails != null); assert(_lastDragUpdateDetails != null);
if (widget.onDragSelectionUpdate != null) { if (widget.onDragSelectionUpdate != null) {
widget.onDragSelectionUpdate( widget.onDragSelectionUpdate!(
_lastDragStartDetails, _lastDragUpdateDetails); _lastDragStartDetails!, _lastDragUpdateDetails!);
} }
_dragUpdateThrottleTimer = null; _dragUpdateThrottleTimer = null;
_lastDragUpdateDetails = null; _lastDragUpdateDetails = null;
@ -607,11 +597,11 @@ class _EditorTextSelectionGestureDetectorState
_handleDragEnd(DragEndDetails details) { _handleDragEnd(DragEndDetails details) {
assert(_lastDragStartDetails != null); assert(_lastDragStartDetails != null);
if (_dragUpdateThrottleTimer != null) { if (_dragUpdateThrottleTimer != null) {
_dragUpdateThrottleTimer.cancel(); _dragUpdateThrottleTimer!.cancel();
_handleDragUpdateThrottled(); _handleDragUpdateThrottled();
} }
if (widget.onDragSelectionEnd != null) { if (widget.onDragSelectionEnd != null) {
widget.onDragSelectionEnd(details); widget.onDragSelectionEnd!(details);
} }
_dragUpdateThrottleTimer = null; _dragUpdateThrottleTimer = null;
_lastDragStartDetails = null; _lastDragStartDetails = null;
@ -622,31 +612,31 @@ class _EditorTextSelectionGestureDetectorState
_doubleTapTimer?.cancel(); _doubleTapTimer?.cancel();
_doubleTapTimer = null; _doubleTapTimer = null;
if (widget.onForcePressStart != null) { if (widget.onForcePressStart != null) {
widget.onForcePressStart(details); widget.onForcePressStart!(details);
} }
} }
_forcePressEnded(ForcePressDetails details) { _forcePressEnded(ForcePressDetails details) {
if (widget.onForcePressEnd != null) { if (widget.onForcePressEnd != null) {
widget.onForcePressEnd(details); widget.onForcePressEnd!(details);
} }
} }
_handleLongPressStart(LongPressStartDetails details) { _handleLongPressStart(LongPressStartDetails details) {
if (!_isDoubleTap && widget.onSingleLongTapStart != null) { if (!_isDoubleTap && widget.onSingleLongTapStart != null) {
widget.onSingleLongTapStart(details); widget.onSingleLongTapStart!(details);
} }
} }
_handleLongPressMoveUpdate(LongPressMoveUpdateDetails details) { _handleLongPressMoveUpdate(LongPressMoveUpdateDetails details) {
if (!_isDoubleTap && widget.onSingleLongTapMoveUpdate != null) { if (!_isDoubleTap && widget.onSingleLongTapMoveUpdate != null) {
widget.onSingleLongTapMoveUpdate(details); widget.onSingleLongTapMoveUpdate!(details);
} }
} }
_handleLongPressEnd(LongPressEndDetails details) { _handleLongPressEnd(LongPressEndDetails details) {
if (!_isDoubleTap && widget.onSingleLongTapEnd != null) { if (!_isDoubleTap && widget.onSingleLongTapEnd != null) {
widget.onSingleLongTapEnd(details); widget.onSingleLongTapEnd!(details);
} }
_isDoubleTap = false; _isDoubleTap = false;
} }
@ -657,12 +647,11 @@ class _EditorTextSelectionGestureDetectorState
} }
bool _isWithinDoubleTapTolerance(Offset secondTapOffset) { bool _isWithinDoubleTapTolerance(Offset secondTapOffset) {
assert(secondTapOffset != null);
if (_lastTapOffset == null) { if (_lastTapOffset == null) {
return false; return false;
} }
return (secondTapOffset - _lastTapOffset).distance <= kDoubleTapSlop; return (secondTapOffset - _lastTapOffset!).distance <= kDoubleTapSlop;
} }
@override @override
@ -738,7 +727,7 @@ class _EditorTextSelectionGestureDetectorState
class _TransparentTapGestureRecognizer extends TapGestureRecognizer { class _TransparentTapGestureRecognizer extends TapGestureRecognizer {
_TransparentTapGestureRecognizer({ _TransparentTapGestureRecognizer({
Object debugOwner, Object? debugOwner,
}) : super(debugOwner: debugOwner); }) : super(debugOwner: debugOwner);
@override @override

@ -1,10 +1,12 @@
import 'dart:io'; import 'dart:io';
import 'package:file_picker/file_picker.dart'; import 'package:file_picker/file_picker.dart';
//import 'package:filesystem_picker/filesystem_picker.dart';
import 'package:filesystem_picker/filesystem_picker.dart'; import 'package:filesystem_picker/filesystem_picker.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
//import 'package:flutter_colorpicker/flutter_colorpicker.dart';
import 'package:flutter_colorpicker/flutter_colorpicker.dart'; import 'package:flutter_colorpicker/flutter_colorpicker.dart';
import 'package:flutter_quill/models/documents/attribute.dart'; import 'package:flutter_quill/models/documents/attribute.dart';
import 'package:flutter_quill/models/documents/nodes/embed.dart'; import 'package:flutter_quill/models/documents/nodes/embed.dart';
@ -18,7 +20,7 @@ import 'controller.dart';
double iconSize = 18.0; double iconSize = 18.0;
double kToolbarHeight = iconSize * 2; double kToolbarHeight = iconSize * 2;
typedef OnImagePickCallback = Future<String> Function(File file); typedef OnImagePickCallback = Future<String?> Function(File? file);
typedef ImagePickImpl = Future<String> Function(ImageSource source); typedef ImagePickImpl = Future<String> Function(ImageSource source);
class InsertEmbedButton extends StatelessWidget { class InsertEmbedButton extends StatelessWidget {
@ -26,9 +28,9 @@ class InsertEmbedButton extends StatelessWidget {
final IconData icon; final IconData icon;
const InsertEmbedButton({ const InsertEmbedButton({
Key key, Key? key,
@required this.controller, required this.controller,
@required this.icon, required this.icon,
}) : super(key: key); }) : super(key: key);
@override @override
@ -54,11 +56,11 @@ class InsertEmbedButton extends StatelessWidget {
class LinkStyleButton extends StatefulWidget { class LinkStyleButton extends StatefulWidget {
final QuillController controller; final QuillController controller;
final IconData icon; final IconData? icon;
const LinkStyleButton({ const LinkStyleButton({
Key key, Key? key,
@required this.controller, required this.controller,
this.icon, this.icon,
}) : super(key: key); }) : super(key: key);
@ -96,7 +98,8 @@ class _LinkStyleButtonState extends State<LinkStyleButton> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
final theme = Theme.of(context); final theme = Theme.of(context);
final isEnabled = !widget.controller.selection.isCollapsed; final isEnabled = !widget.controller.selection.isCollapsed;
final pressedHandler = isEnabled ? () => _openLinkDialog(context) : null; final VoidCallback? pressedHandler =
isEnabled ? () => _openLinkDialog(context) : null;
return QuillIconButton( return QuillIconButton(
highlightElevation: 0, highlightElevation: 0,
hoverElevation: 0, hoverElevation: 0,
@ -120,7 +123,7 @@ class _LinkStyleButtonState extends State<LinkStyleButton> {
).then(_linkSubmitted); ).then(_linkSubmitted);
} }
void _linkSubmitted(String value) { void _linkSubmitted(String? value) {
if (value == null || value.isEmpty) { if (value == null || value.isEmpty) {
return; return;
} }
@ -129,7 +132,7 @@ class _LinkStyleButtonState extends State<LinkStyleButton> {
} }
class _LinkDialog extends StatefulWidget { class _LinkDialog extends StatefulWidget {
const _LinkDialog({Key key}) : super(key: key); const _LinkDialog({Key? key}) : super(key: key);
@override @override
_LinkDialogState createState() => _LinkDialogState(); _LinkDialogState createState() => _LinkDialogState();
@ -171,7 +174,7 @@ typedef ToggleStyleButtonBuilder = Widget Function(
Attribute attribute, Attribute attribute,
IconData icon, IconData icon,
bool isToggled, bool isToggled,
VoidCallback onPressed, VoidCallback? onPressed,
); );
class ToggleStyleButton extends StatefulWidget { class ToggleStyleButton extends StatefulWidget {
@ -184,23 +187,19 @@ class ToggleStyleButton extends StatefulWidget {
final ToggleStyleButtonBuilder childBuilder; final ToggleStyleButtonBuilder childBuilder;
ToggleStyleButton({ ToggleStyleButton({
Key key, Key? key,
@required this.attribute, required this.attribute,
@required this.icon, required this.icon,
@required this.controller, required this.controller,
this.childBuilder = defaultToggleStyleButtonBuilder, this.childBuilder = defaultToggleStyleButtonBuilder,
}) : assert(attribute.value != null), }) : super(key: key);
assert(icon != null),
assert(controller != null),
assert(childBuilder != null),
super(key: key);
@override @override
_ToggleStyleButtonState createState() => _ToggleStyleButtonState(); _ToggleStyleButtonState createState() => _ToggleStyleButtonState();
} }
class _ToggleStyleButtonState extends State<ToggleStyleButton> { class _ToggleStyleButtonState extends State<ToggleStyleButton> {
bool _isToggled; bool? _isToggled;
Style get _selectionStyle => widget.controller.getSelectionStyle(); Style get _selectionStyle => widget.controller.getSelectionStyle();
@ -220,7 +219,7 @@ class _ToggleStyleButtonState extends State<ToggleStyleButton> {
bool _getIsToggled(Map<String, Attribute> attrs) { bool _getIsToggled(Map<String, Attribute> attrs) {
if (widget.attribute.key == Attribute.list.key) { if (widget.attribute.key == Attribute.list.key) {
Attribute attribute = attrs[widget.attribute.key]; Attribute? attribute = attrs[widget.attribute.key];
if (attribute == null) { if (attribute == null) {
return false; return false;
} }
@ -252,11 +251,11 @@ class _ToggleStyleButtonState extends State<ToggleStyleButton> {
final isEnabled = final isEnabled =
!isInCodeBlock || widget.attribute.key == Attribute.codeBlock.key; !isInCodeBlock || widget.attribute.key == Attribute.codeBlock.key;
return widget.childBuilder(context, widget.attribute, widget.icon, return widget.childBuilder(context, widget.attribute, widget.icon,
_isToggled, isEnabled ? _toggleAttribute : null); _isToggled!, isEnabled ? _toggleAttribute : null);
} }
_toggleAttribute() { _toggleAttribute() {
widget.controller.formatSelection(_isToggled widget.controller.formatSelection(_isToggled!
? Attribute.clone(widget.attribute, null) ? Attribute.clone(widget.attribute, null)
: widget.attribute); : widget.attribute);
} }
@ -272,22 +271,19 @@ class ToggleCheckListButton extends StatefulWidget {
final Attribute attribute; final Attribute attribute;
ToggleCheckListButton({ ToggleCheckListButton({
Key key, Key? key,
@required this.icon, required this.icon,
@required this.controller, required this.controller,
this.childBuilder = defaultToggleStyleButtonBuilder, this.childBuilder = defaultToggleStyleButtonBuilder,
@required this.attribute, required this.attribute,
}) : assert(icon != null), }) : super(key: key);
assert(controller != null),
assert(childBuilder != null),
super(key: key);
@override @override
_ToggleCheckListButtonState createState() => _ToggleCheckListButtonState(); _ToggleCheckListButtonState createState() => _ToggleCheckListButtonState();
} }
class _ToggleCheckListButtonState extends State<ToggleCheckListButton> { class _ToggleCheckListButtonState extends State<ToggleCheckListButton> {
bool _isToggled; bool? _isToggled;
Style get _selectionStyle => widget.controller.getSelectionStyle(); Style get _selectionStyle => widget.controller.getSelectionStyle();
@ -307,7 +303,7 @@ class _ToggleCheckListButtonState extends State<ToggleCheckListButton> {
bool _getIsToggled(Map<String, Attribute> attrs) { bool _getIsToggled(Map<String, Attribute> attrs) {
if (widget.attribute.key == Attribute.list.key) { if (widget.attribute.key == Attribute.list.key) {
Attribute attribute = attrs[widget.attribute.key]; Attribute? attribute = attrs[widget.attribute.key];
if (attribute == null) { if (attribute == null) {
return false; return false;
} }
@ -340,11 +336,11 @@ class _ToggleCheckListButtonState extends State<ToggleCheckListButton> {
final isEnabled = final isEnabled =
!isInCodeBlock || Attribute.list.key == Attribute.codeBlock.key; !isInCodeBlock || Attribute.list.key == Attribute.codeBlock.key;
return widget.childBuilder(context, Attribute.unchecked, widget.icon, return widget.childBuilder(context, Attribute.unchecked, widget.icon,
_isToggled, isEnabled ? _toggleAttribute : null); _isToggled!, isEnabled ? _toggleAttribute : null);
} }
_toggleAttribute() { _toggleAttribute() {
widget.controller.formatSelection(_isToggled widget.controller.formatSelection(_isToggled!
? Attribute.clone(Attribute.unchecked, null) ? Attribute.clone(Attribute.unchecked, null)
: Attribute.unchecked); : Attribute.unchecked);
} }
@ -355,7 +351,7 @@ Widget defaultToggleStyleButtonBuilder(
Attribute attribute, Attribute attribute,
IconData icon, IconData icon,
bool isToggled, bool isToggled,
VoidCallback onPressed, VoidCallback? onPressed,
) { ) {
final theme = Theme.of(context); final theme = Theme.of(context);
final isEnabled = onPressed != null; final isEnabled = onPressed != null;
@ -378,7 +374,7 @@ Widget defaultToggleStyleButtonBuilder(
class SelectHeaderStyleButton extends StatefulWidget { class SelectHeaderStyleButton extends StatefulWidget {
final QuillController controller; final QuillController controller;
const SelectHeaderStyleButton({Key key, @required this.controller}) const SelectHeaderStyleButton({Key? key, required this.controller})
: super(key: key); : super(key: key);
@override @override
@ -387,7 +383,7 @@ class SelectHeaderStyleButton extends StatefulWidget {
} }
class _SelectHeaderStyleButtonState extends State<SelectHeaderStyleButton> { class _SelectHeaderStyleButtonState extends State<SelectHeaderStyleButton> {
Attribute _value; Attribute? _value;
Style get _selectionStyle => widget.controller.getSelectionStyle(); Style get _selectionStyle => widget.controller.getSelectionStyle();
@ -431,7 +427,7 @@ class _SelectHeaderStyleButtonState extends State<SelectHeaderStyleButton> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return _selectHeadingStyleButtonBuilder(context, _value, _selectAttribute); return _selectHeadingStyleButtonBuilder(context, _value!, _selectAttribute);
} }
} }
@ -453,35 +449,35 @@ Widget _selectHeadingStyleButtonBuilder(
fillColor: Theme.of(context).canvasColor, fillColor: Theme.of(context).canvasColor,
child: Text( child: Text(
!kIsWeb !kIsWeb
? _valueToText[value] ? _valueToText[value]!
: _valueToText[value.key == "header" : _valueToText[value.key == "header"
? Attribute.header ? Attribute.header
: (value.key == "h1") : (value.key == "h1")
? Attribute.h1 ? Attribute.h1
: (value.key == "h2") : (value.key == "h2")
? Attribute.h2 ? Attribute.h2
: Attribute.h3], : Attribute.h3]!,
style: TextStyle(fontSize: 13, fontWeight: FontWeight.w600), style: TextStyle(fontSize: 13, fontWeight: FontWeight.w600),
), ),
initialValue: value, initialValue: value,
items: [ items: [
PopupMenuItem( PopupMenuItem(
child: Text(_valueToText[Attribute.header], style: style), child: Text(_valueToText[Attribute.header]!, style: style),
value: Attribute.header, value: Attribute.header,
height: iconSize * 1.77, height: iconSize * 1.77,
), ),
PopupMenuItem( PopupMenuItem(
child: Text(_valueToText[Attribute.h1], style: style), child: Text(_valueToText[Attribute.h1]!, style: style),
value: Attribute.h1, value: Attribute.h1,
height: iconSize * 1.77, height: iconSize * 1.77,
), ),
PopupMenuItem( PopupMenuItem(
child: Text(_valueToText[Attribute.h2], style: style), child: Text(_valueToText[Attribute.h2]!, style: style),
value: Attribute.h2, value: Attribute.h2,
height: iconSize * 1.77, height: iconSize * 1.77,
), ),
PopupMenuItem( PopupMenuItem(
child: Text(_valueToText[Attribute.h3], style: style), child: Text(_valueToText[Attribute.h3]!, style: style),
value: Attribute.h3, value: Attribute.h3,
height: iconSize * 1.77, height: iconSize * 1.77,
), ),
@ -495,43 +491,41 @@ class ImageButton extends StatefulWidget {
final QuillController controller; final QuillController controller;
final OnImagePickCallback onImagePickCallback; final OnImagePickCallback? onImagePickCallback;
final ImagePickImpl imagePickImpl; final ImagePickImpl? imagePickImpl;
final ImageSource imageSource; final ImageSource imageSource;
ImageButton( ImageButton(
{Key key, {Key? key,
@required this.icon, required this.icon,
@required this.controller, required this.controller,
@required this.imageSource, required this.imageSource,
this.onImagePickCallback, this.onImagePickCallback,
this.imagePickImpl}) this.imagePickImpl})
: assert(icon != null), : super(key: key);
assert(controller != null),
super(key: key);
@override @override
_ImageButtonState createState() => _ImageButtonState(); _ImageButtonState createState() => _ImageButtonState();
} }
class _ImageButtonState extends State<ImageButton> { class _ImageButtonState extends State<ImageButton> {
List<PlatformFile> _paths; List<PlatformFile>? _paths;
String _extension; String? _extension;
final _picker = ImagePicker(); final _picker = ImagePicker();
FileType _pickingType = FileType.any; FileType _pickingType = FileType.any;
Future<String> _pickImage(ImageSource source) async { Future<String?> _pickImage(ImageSource imageSource) async {
final PickedFile pickedFile = await _picker.getImage(source: source); final PickedFile? pickedFile = await _picker.getImage(source: imageSource);
if (pickedFile == null) return null; if (pickedFile == null) return null;
final File file = File(pickedFile.path); final File? file = File(pickedFile.path);
if (file == null || widget.onImagePickCallback == null) return null; if (file == null || widget.onImagePickCallback == null) return null;
// We simply return the absolute path to selected file. // We simply return the absolute path to selected file.
try { try {
String url = await widget.onImagePickCallback(file); String? url = await widget.onImagePickCallback!(file);
print('Image uploaded and its url is $url'); print('Image uploaded and its url is $url');
return url; return url;
} catch (error) { } catch (error) {
@ -540,13 +534,13 @@ class _ImageButtonState extends State<ImageButton> {
return null; return null;
} }
Future<String> _pickImageWeb() async { Future<String?> _pickImageWeb() async {
try { try {
_paths = (await FilePicker.platform.pickFiles( _paths = (await FilePicker.platform.pickFiles(
type: _pickingType, type: _pickingType,
allowMultiple: false, allowMultiple: false,
allowedExtensions: (_extension?.isNotEmpty ?? false) allowedExtensions: (_extension?.isNotEmpty ?? false)
? _extension?.replaceAll(' ', '')?.split(',') ? _extension?.replaceAll(' ', '').split(',')
: null, : null,
)) ))
?.files; ?.files;
@ -556,14 +550,15 @@ class _ImageButtonState extends State<ImageButton> {
print(ex); print(ex);
} }
var _fileName = var _fileName =
_paths != null ? _paths.map((e) => e.name).toString() : '...'; _paths != null ? _paths!.map((e) => e.name).toString() : '...';
if (_paths != null) { if (_paths != null) {
File file = File(_fileName); File file = File(_fileName);
if (file == null || widget.onImagePickCallback == null) return null; //The condition is never true because File constructor never gives null.
//if (file == null || widget.onImagePickCallback == null) return null;
// We simply return the absolute path to selected file. // We simply return the absolute path to selected file.
try { try {
String url = await widget.onImagePickCallback(file); String? url = await widget.onImagePickCallback!(file);
print('Image uploaded and its url is $url'); print('Image uploaded and its url is $url');
return url; return url;
} catch (error) { } catch (error) {
@ -576,7 +571,7 @@ class _ImageButtonState extends State<ImageButton> {
return null; return null;
} }
Future<String> _pickImageDesktop() async { Future<String?> _pickImageDesktop() async {
try { try {
var filePath = await FilesystemPicker.open( var filePath = await FilesystemPicker.open(
context: context, context: context,
@ -587,7 +582,7 @@ class _ImageButtonState extends State<ImageButton> {
if (filePath == null || filePath.isEmpty) return null; if (filePath == null || filePath.isEmpty) return null;
final File file = File(filePath); final File file = File(filePath);
String url = await widget.onImagePickCallback(file); String? url = await widget.onImagePickCallback!(file);
print('Image uploaded and its url is $url'); print('Image uploaded and its url is $url');
return url; return url;
} catch (error) { } catch (error) {
@ -610,9 +605,9 @@ class _ImageButtonState extends State<ImageButton> {
onPressed: () { onPressed: () {
final index = widget.controller.selection.baseOffset; final index = widget.controller.selection.baseOffset;
final length = widget.controller.selection.extentOffset - index; final length = widget.controller.selection.extentOffset - index;
Future<String> image; Future<String?> image;
if (widget.imagePickImpl != null) { if (widget.imagePickImpl != null) {
image = widget.imagePickImpl(widget.imageSource); image = widget.imagePickImpl!(widget.imageSource);
} else { } else {
if (kIsWeb) { if (kIsWeb) {
image = _pickImageWeb(); image = _pickImageWeb();
@ -644,24 +639,21 @@ class ColorButton extends StatefulWidget {
final QuillController controller; final QuillController controller;
ColorButton( ColorButton(
{Key key, {Key? key,
@required this.icon, required this.icon,
@required this.controller, required this.controller,
@required this.background}) required this.background})
: assert(icon != null), : super(key: key);
assert(controller != null),
assert(background != null),
super(key: key);
@override @override
_ColorButtonState createState() => _ColorButtonState(); _ColorButtonState createState() => _ColorButtonState();
} }
class _ColorButtonState extends State<ColorButton> { class _ColorButtonState extends State<ColorButton> {
bool _isToggledColor; bool? _isToggledColor;
bool _isToggledBackground; bool? _isToggledBackground;
bool _isWhite; bool? _isWhite;
bool _isWhitebackground; bool? _isWhitebackground;
Style get _selectionStyle => widget.controller.getSelectionStyle(); Style get _selectionStyle => widget.controller.getSelectionStyle();
@ -671,10 +663,10 @@ class _ColorButtonState extends State<ColorButton> {
_getIsToggledColor(widget.controller.getSelectionStyle().attributes); _getIsToggledColor(widget.controller.getSelectionStyle().attributes);
_isToggledBackground = _getIsToggledBackground( _isToggledBackground = _getIsToggledBackground(
widget.controller.getSelectionStyle().attributes); widget.controller.getSelectionStyle().attributes);
_isWhite = _isToggledColor && _isWhite = _isToggledColor! &&
_selectionStyle.attributes["color"].value == '#ffffff'; _selectionStyle.attributes["color"]!.value == '#ffffff';
_isWhitebackground = _isToggledBackground && _isWhitebackground = _isToggledBackground! &&
_selectionStyle.attributes["background"].value == '#ffffff'; _selectionStyle.attributes["background"]!.value == '#ffffff';
}); });
} }
@ -683,10 +675,10 @@ class _ColorButtonState extends State<ColorButton> {
super.initState(); super.initState();
_isToggledColor = _getIsToggledColor(_selectionStyle.attributes); _isToggledColor = _getIsToggledColor(_selectionStyle.attributes);
_isToggledBackground = _getIsToggledBackground(_selectionStyle.attributes); _isToggledBackground = _getIsToggledBackground(_selectionStyle.attributes);
_isWhite = _isToggledColor && _isWhite = _isToggledColor! &&
_selectionStyle.attributes["color"].value == '#ffffff'; _selectionStyle.attributes["color"]!.value == '#ffffff';
_isWhitebackground = _isToggledBackground && _isWhitebackground = _isToggledBackground! &&
_selectionStyle.attributes["background"].value == '#ffffff'; _selectionStyle.attributes["background"]!.value == '#ffffff';
widget.controller.addListener(_didChangeEditingValue); widget.controller.addListener(_didChangeEditingValue);
} }
@ -707,10 +699,10 @@ class _ColorButtonState extends State<ColorButton> {
_isToggledColor = _getIsToggledColor(_selectionStyle.attributes); _isToggledColor = _getIsToggledColor(_selectionStyle.attributes);
_isToggledBackground = _isToggledBackground =
_getIsToggledBackground(_selectionStyle.attributes); _getIsToggledBackground(_selectionStyle.attributes);
_isWhite = _isToggledColor && _isWhite = _isToggledColor! &&
_selectionStyle.attributes["color"].value == '#ffffff'; _selectionStyle.attributes["color"]!.value == '#ffffff';
_isWhitebackground = _isToggledBackground && _isWhitebackground = _isToggledBackground! &&
_selectionStyle.attributes["background"].value == '#ffffff'; _selectionStyle.attributes["background"]!.value == '#ffffff';
} }
} }
@ -723,20 +715,20 @@ class _ColorButtonState extends State<ColorButton> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final theme = Theme.of(context); final theme = Theme.of(context);
Color iconColor = _isToggledColor && !widget.background && !_isWhite Color iconColor = _isToggledColor! && !widget.background && !_isWhite!
? stringToColor(_selectionStyle.attributes["color"].value) ? stringToColor(_selectionStyle.attributes["color"]!.value)
: theme.iconTheme.color; : theme.iconTheme.color!;
Color iconColorBackground = Color iconColorBackground =
_isToggledBackground && widget.background && !_isWhitebackground _isToggledBackground! && widget.background && !_isWhitebackground!
? stringToColor(_selectionStyle.attributes["background"].value) ? stringToColor(_selectionStyle.attributes["background"]!.value)
: theme.iconTheme.color; : theme.iconTheme.color!;
Color fillColor = _isToggledColor && !widget.background && _isWhite Color fillColor = _isToggledColor! && !widget.background && _isWhite!
? stringToColor('#ffffff') ? stringToColor('#ffffff')
: theme.canvasColor; : theme.canvasColor;
Color fillColorBackground = Color fillColorBackground =
_isToggledBackground && widget.background && _isWhitebackground _isToggledBackground! && widget.background && _isWhitebackground!
? stringToColor('#ffffff') ? stringToColor('#ffffff')
: theme.canvasColor; : theme.canvasColor;
@ -785,29 +777,26 @@ class HistoryButton extends StatefulWidget {
final QuillController controller; final QuillController controller;
HistoryButton( HistoryButton(
{Key key, {Key? key,
@required this.icon, required this.icon,
@required this.controller, required this.controller,
@required this.undo}) required this.undo})
: assert(icon != null), : super(key: key);
assert(controller != null),
assert(undo != null),
super(key: key);
@override @override
_HistoryButtonState createState() => _HistoryButtonState(); _HistoryButtonState createState() => _HistoryButtonState();
} }
class _HistoryButtonState extends State<HistoryButton> { class _HistoryButtonState extends State<HistoryButton> {
Color _iconColor; Color? _iconColor;
ThemeData theme; ThemeData? theme;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
theme = Theme.of(context); theme = Theme.of(context);
_setIconColor(); _setIconColor();
final fillColor = theme.canvasColor; final fillColor = theme!.canvasColor;
widget.controller.changes.listen((event) async { widget.controller.changes.listen((event) async {
_setIconColor(); _setIconColor();
}); });
@ -827,14 +816,14 @@ class _HistoryButtonState extends State<HistoryButton> {
if (widget.undo) { if (widget.undo) {
setState(() { setState(() {
_iconColor = widget.controller.hasUndo _iconColor = widget.controller.hasUndo
? theme.iconTheme.color ? theme!.iconTheme.color!
: theme.disabledColor; : theme!.disabledColor;
}); });
} else { } else {
setState(() { setState(() {
_iconColor = widget.controller.hasRedo _iconColor = widget.controller.hasRedo
? theme.iconTheme.color ? theme!.iconTheme.color!
: theme.disabledColor; : theme!.disabledColor;
}); });
} }
} }
@ -860,14 +849,11 @@ class IndentButton extends StatefulWidget {
final bool isIncrease; final bool isIncrease;
IndentButton( IndentButton(
{Key key, {Key? key,
@required this.icon, required this.icon,
@required this.controller, required this.controller,
@required this.isIncrease}) required this.isIncrease})
: assert(icon != null), : super(key: key);
assert(controller != null),
assert(isIncrease != null),
super(key: key);
@override @override
_IndentButtonState createState() => _IndentButtonState(); _IndentButtonState createState() => _IndentButtonState();
@ -917,10 +903,8 @@ class ClearFormatButton extends StatefulWidget {
final QuillController controller; final QuillController controller;
ClearFormatButton({Key key, @required this.icon, @required this.controller}) ClearFormatButton({Key? key, required this.icon, required this.controller})
: assert(icon != null), : super(key: key);
assert(controller != null),
super(key: key);
@override @override
_ClearFormatButtonState createState() => _ClearFormatButtonState(); _ClearFormatButtonState createState() => _ClearFormatButtonState();
@ -950,11 +934,11 @@ class _ClearFormatButtonState extends State<ClearFormatButton> {
class QuillToolbar extends StatefulWidget implements PreferredSizeWidget { class QuillToolbar extends StatefulWidget implements PreferredSizeWidget {
final List<Widget> children; final List<Widget> children;
const QuillToolbar({Key key, @required this.children}) : super(key: key); const QuillToolbar({Key? key, required this.children}) : super(key: key);
factory QuillToolbar.basic( factory QuillToolbar.basic(
{Key key, {Key? key,
@required QuillController controller, required QuillController controller,
double toolbarIconSize = 18.0, double toolbarIconSize = 18.0,
bool showBoldButton = true, bool showBoldButton = true,
bool showItalicButton = true, bool showItalicButton = true,
@ -973,7 +957,7 @@ class QuillToolbar extends StatefulWidget implements PreferredSizeWidget {
bool showLink = true, bool showLink = true,
bool showHistory = true, bool showHistory = true,
bool showHorizontalRule = false, bool showHorizontalRule = false,
OnImagePickCallback onImagePickCallback}) { OnImagePickCallback? onImagePickCallback}) {
iconSize = toolbarIconSize; iconSize = toolbarIconSize;
return QuillToolbar(key: key, children: [ return QuillToolbar(key: key, children: [
Visibility( Visibility(
@ -1192,16 +1176,16 @@ class _QuillToolbarState extends State<QuillToolbar> {
} }
class QuillIconButton extends StatelessWidget { class QuillIconButton extends StatelessWidget {
final VoidCallback onPressed; final VoidCallback? onPressed;
final Widget icon; final Widget? icon;
final double size; final double size;
final Color fillColor; final Color? fillColor;
final double hoverElevation; final double hoverElevation;
final double highlightElevation; final double highlightElevation;
const QuillIconButton({ const QuillIconButton({
Key key, Key? key,
@required this.onPressed, required this.onPressed,
this.icon, this.icon,
this.size = 40, this.size = 40,
this.fillColor, this.fillColor,
@ -1230,24 +1214,24 @@ class QuillIconButton extends StatelessWidget {
class QuillDropdownButton<T> extends StatefulWidget { class QuillDropdownButton<T> extends StatefulWidget {
final double height; final double height;
final Color fillColor; final Color? fillColor;
final double hoverElevation; final double hoverElevation;
final double highlightElevation; final double highlightElevation;
final Widget child; final Widget child;
final T initialValue; final T initialValue;
final List<PopupMenuEntry<T>> items; final List<PopupMenuEntry<T>> items;
final ValueChanged<T> onSelected; final ValueChanged<T>? onSelected;
const QuillDropdownButton({ const QuillDropdownButton({
Key key, Key? key,
this.height = 40, this.height = 40,
this.fillColor, this.fillColor,
this.hoverElevation = 1, this.hoverElevation = 1,
this.highlightElevation = 1, this.highlightElevation = 1,
@required this.child, required this.child,
@required this.initialValue, required this.initialValue,
@required this.items, required this.items,
@required this.onSelected, required this.onSelected,
}) : super(key: key); }) : super(key: key);
@override @override
@ -1276,7 +1260,8 @@ class _QuillDropdownButtonState<T> extends State<QuillDropdownButton<T>> {
void _showMenu() { void _showMenu() {
final popupMenuTheme = PopupMenuTheme.of(context); final popupMenuTheme = PopupMenuTheme.of(context);
final button = context.findRenderObject() as RenderBox; final button = context.findRenderObject() as RenderBox;
final overlay = Overlay.of(context).context.findRenderObject() as RenderBox; final overlay =
Overlay.of(context)!.context.findRenderObject() as RenderBox;
final position = RelativeRect.fromRect( final position = RelativeRect.fromRect(
Rect.fromPoints( Rect.fromPoints(
button.localToGlobal(Offset.zero, ancestor: overlay), button.localToGlobal(Offset.zero, ancestor: overlay),
@ -1296,14 +1281,14 @@ class _QuillDropdownButtonState<T> extends State<QuillDropdownButton<T>> {
// widget.shape ?? popupMenuTheme.shape, // widget.shape ?? popupMenuTheme.shape,
color: popupMenuTheme.color, // widget.color ?? popupMenuTheme.color, color: popupMenuTheme.color, // widget.color ?? popupMenuTheme.color,
// captureInheritedThemes: widget.captureInheritedThemes, // captureInheritedThemes: widget.captureInheritedThemes,
).then((T newValue) { ).then((T? newValue) {
if (!mounted) return null; if (!mounted) return null;
if (newValue == null) { if (newValue == null) {
// if (widget.onCanceled != null) widget.onCanceled(); // if (widget.onCanceled != null) widget.onCanceled();
return null; return null;
} }
if (widget.onSelected != null) { if (widget.onSelected != null) {
widget.onSelected(newValue); widget.onSelected!(newValue);
} }
}); });
} }

@ -56,7 +56,7 @@ packages:
name: csslib name: csslib
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.16.2" version: "0.17.0"
fake_async: fake_async:
dependency: transitive dependency: transitive
description: description:
@ -91,7 +91,7 @@ packages:
name: filesystem_picker name: filesystem_picker
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.0.4" version: "2.0.0-nullsafety.0"
flutter: flutter:
dependency: "direct main" dependency: "direct main"
description: flutter description: flutter
@ -103,7 +103,7 @@ packages:
name: flutter_colorpicker name: flutter_colorpicker
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.3.5" version: "0.4.0-nullsafety.0"
flutter_keyboard_visibility: flutter_keyboard_visibility:
dependency: "direct main" dependency: "direct main"
description: description:
@ -148,7 +148,7 @@ packages:
name: html name: html
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.14.0+4" version: "0.15.0"
http: http:
dependency: transitive dependency: transitive
description: description:
@ -169,7 +169,14 @@ packages:
name: image_picker name: image_picker
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.7.2+1" version: "0.7.3"
image_picker_for_web:
dependency: transitive
description:
name: image_picker_for_web
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.0"
image_picker_platform_interface: image_picker_platform_interface:
dependency: transitive dependency: transitive
description: description:
@ -293,7 +300,7 @@ packages:
name: source_span name: source_span
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.8.1" version: "1.8.0"
stack_trace: stack_trace:
dependency: transitive dependency: transitive
description: description:
@ -321,7 +328,7 @@ packages:
name: string_validator name: string_validator
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.1.4" version: "0.3.0"
term_glyph: term_glyph:
dependency: transitive dependency: transitive
description: description:
@ -356,21 +363,14 @@ packages:
name: universal_html name: universal_html
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.2.4" version: "2.0.4"
universal_io: universal_io:
dependency: transitive dependency: transitive
description: description:
name: universal_io name: universal_io
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.0.0" version: "2.0.1"
universal_ui:
dependency: "direct main"
description:
name: universal_ui
url: "https://pub.dartlang.org"
source: hosted
version: "0.0.8"
url_launcher: url_launcher:
dependency: "direct main" dependency: "direct main"
description: description:
@ -426,7 +426,7 @@ packages:
name: win32 name: win32
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.0.3" version: "2.0.4"
xdg_directories: xdg_directories:
dependency: transitive dependency: transitive
description: description:
@ -434,13 +434,6 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.2.0" version: "0.2.0"
zone_local:
dependency: transitive
description:
name: zone_local
url: "https://pub.dartlang.org"
source: hosted
version: "0.1.2"
sdks: sdks:
dart: ">=2.12.0 <3.0.0" dart: ">=2.12.0 <3.0.0"
flutter: ">=1.22.0" flutter: ">=1.24.0-10.2.pre"

@ -6,7 +6,7 @@ homepage: https://bulletjournal.us/home/index.html
repository: https://github.com/singerdmx/flutter-quill.git repository: https://github.com/singerdmx/flutter-quill.git
environment: environment:
sdk: ">=2.7.0 <3.0.0" sdk: ">=2.12.0 <3.0.0"
flutter: ">=1.17.0" flutter: ">=1.17.0"
dependencies: dependencies:
@ -16,16 +16,16 @@ dependencies:
collection: ^1.15.0 collection: ^1.15.0
tuple: ^2.0.0 tuple: ^2.0.0
url_launcher: ^6.0.0 url_launcher: ^6.0.0
flutter_colorpicker: ^0.3.5 flutter_colorpicker: ^0.4.0-nullsafety.0
image_picker: ^0.7.2 image_picker: ^0.7.2
photo_view: ^0.11.0 photo_view: ^0.11.0
universal_html: ^1.2.4 universal_html: ^2.0.4
file_picker: ^3.0.0 file_picker: ^3.0.0
filesystem_picker: ^1.0.4 filesystem_picker: ^2.0.0-nullsafety.0
path_provider: ^2.0.1 path_provider: ^2.0.1
string_validator: ^0.1.4 string_validator: ^0.3.0
flutter_keyboard_visibility: ^5.0.0 flutter_keyboard_visibility: ^5.0.0
universal_ui: ^0.0.8 # universal_ui: ^0.0.8

Loading…
Cancel
Save