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. 93
      lib/models/documents/nodes/leaf.dart
  15. 92
      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. 275
      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 {
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"

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

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

@ -14,14 +14,14 @@ class DemoScaffold extends StatefulWidget {
/// Filename of the document to load into the editor.
final String documentFilename;
final DemoContentBuilder builder;
final List<Widget> actions;
final Widget floatingActionButton;
final List<Widget>? actions;
final Widget? floatingActionButton;
final bool showToolbar;
const DemoScaffold({
Key key,
@required this.documentFilename,
@required this.builder,
Key? key,
required this.documentFilename,
required this.builder,
this.actions,
this.showToolbar = true,
this.floatingActionButton,
@ -33,7 +33,7 @@ class DemoScaffold extends StatefulWidget {
class _DemoScaffoldState extends State<DemoScaffold> {
final _scaffoldKey = GlobalKey<ScaffoldState>();
QuillController _controller;
QuillController? _controller;
bool _loading = false;
@ -92,13 +92,13 @@ class _DemoScaffoldState extends State<DemoScaffold> {
),
title: _loading || widget.showToolbar == false
? null
: QuillToolbar.basic(controller: _controller),
: QuillToolbar.basic(controller: _controller!),
actions: actions,
),
floatingActionButton: widget.floatingActionButton,
body: _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 readOnly;
final bool enableInteractiveSelection;
final double minHeight;
final double maxHeight;
final double? minHeight;
final double? maxHeight;
final bool expands;
final TextCapitalization textCapitalization;
final Brightness keyboardAppearance;
final ScrollPhysics scrollPhysics;
final ValueChanged<String> onLaunchUrl;
final InputDecoration decoration;
final Widget toolbar;
final EmbedBuilder embedBuilder;
final ScrollPhysics? scrollPhysics;
final ValueChanged<String>? onLaunchUrl;
final InputDecoration? decoration;
final Widget? toolbar;
final EmbedBuilder? embedBuilder;
QuillField({
Key key,
@required this.controller,
this.focusNode,
this.scrollController,
Key? key,
required this.controller,
required this.focusNode,
required this.scrollController,
this.scrollable = true,
this.padding = EdgeInsets.zero,
this.autofocus = false,
@ -53,7 +53,7 @@ class QuillField extends StatefulWidget {
}
class _QuillFieldState extends State<QuillField> {
bool _focused;
bool? _focused;
void _editorFocusChanged() {
setState(() {
@ -105,8 +105,8 @@ class _QuillFieldState extends State<QuillField> {
children: [
child,
Visibility(
child: widget.toolbar,
visible: _focused,
child: widget.toolbar!,
visible: _focused!,
maintainSize: true,
maintainAnimation: true,
maintainState: true,
@ -118,7 +118,7 @@ class _QuillFieldState extends State<QuillField> {
return AnimatedBuilder(
animation:
Listenable.merge(<Listenable>[widget.focusNode, widget.controller]),
builder: (BuildContext context, Widget child) {
builder: (BuildContext context, Widget? child) {
return InputDecorator(
decoration: _getEffectiveDecoration(),
isFocused: widget.focusNode.hasFocus,

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

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

@ -8,33 +8,33 @@ enum AttributeScope {
}
class Attribute<T> {
final String key;
final AttributeScope scope;
final T value;
final String? key;
final AttributeScope? scope;
final T? value;
Attribute(this.key, this.scope, this.value);
static final Map<String, Attribute> _registry = {
Attribute.bold.key: Attribute.bold,
Attribute.italic.key: Attribute.italic,
Attribute.underline.key: Attribute.underline,
Attribute.strikeThrough.key: Attribute.strikeThrough,
Attribute.font.key: Attribute.font,
Attribute.size.key: Attribute.size,
Attribute.link.key: Attribute.link,
Attribute.color.key: Attribute.color,
Attribute.background.key: Attribute.background,
Attribute.placeholder.key: Attribute.placeholder,
Attribute.header.key: Attribute.header,
Attribute.indent.key: Attribute.indent,
Attribute.align.key: Attribute.align,
Attribute.list.key: Attribute.list,
Attribute.codeBlock.key: Attribute.codeBlock,
Attribute.blockQuote.key: Attribute.blockQuote,
Attribute.width.key: Attribute.width,
Attribute.height.key: Attribute.height,
Attribute.style.key: Attribute.style,
Attribute.token.key: Attribute.token,
Attribute.bold.key!: Attribute.bold,
Attribute.italic.key!: Attribute.italic,
Attribute.underline.key!: Attribute.underline,
Attribute.strikeThrough.key!: Attribute.strikeThrough,
Attribute.font.key!: Attribute.font,
Attribute.size.key!: Attribute.size,
Attribute.link.key!: Attribute.link,
Attribute.color.key!: Attribute.color,
Attribute.background.key!: Attribute.background,
Attribute.placeholder.key!: Attribute.placeholder,
Attribute.header.key!: Attribute.header,
Attribute.indent.key!: Attribute.indent,
Attribute.align.key!: Attribute.align,
Attribute.list.key!: Attribute.list,
Attribute.codeBlock.key!: Attribute.codeBlock,
Attribute.blockQuote.key!: Attribute.blockQuote,
Attribute.width.key!: Attribute.width,
Attribute.height.key!: Attribute.height,
Attribute.style.key!: Attribute.style,
Attribute.token.key!: Attribute.token,
};
static final BoldAttribute bold = BoldAttribute();
@ -78,31 +78,31 @@ class Attribute<T> {
static final TokenAttribute token = TokenAttribute(null);
static final Set<String> inlineKeys = {
Attribute.bold.key,
Attribute.italic.key,
Attribute.underline.key,
Attribute.strikeThrough.key,
Attribute.link.key,
Attribute.color.key,
Attribute.background.key,
Attribute.placeholder.key,
Attribute.bold.key!,
Attribute.italic.key!,
Attribute.underline.key!,
Attribute.strikeThrough.key!,
Attribute.link.key!,
Attribute.color.key!,
Attribute.background.key!,
Attribute.placeholder.key!,
};
static final Set<String> blockKeys = {
Attribute.header.key,
Attribute.indent.key,
Attribute.align.key,
Attribute.list.key,
Attribute.codeBlock.key,
Attribute.blockQuote.key,
Attribute.header.key!,
Attribute.indent.key!,
Attribute.align.key!,
Attribute.list.key!,
Attribute.codeBlock.key!,
Attribute.blockQuote.key!,
};
static final Set<String> blockKeysExceptHeader = {
Attribute.list.key,
Attribute.indent.key,
Attribute.align.key,
Attribute.codeBlock.key,
Attribute.blockQuote.key,
Attribute.list.key!,
Attribute.indent.key!,
Attribute.align.key!,
Attribute.codeBlock.key!,
Attribute.blockQuote.key!,
};
static Attribute<int> get h1 => HeaderAttribute(level: 1);
@ -158,13 +158,13 @@ class Attribute<T> {
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) {
if (!_registry.containsKey(key)) {
throw ArgumentError.value(key, 'key "$key" not found.');
}
Attribute origin = _registry[key];
Attribute origin = _registry[key]!;
Attribute attribute = clone(origin, value);
return attribute;
}
@ -209,23 +209,23 @@ class StrikeThroughAttribute extends Attribute<bool> {
}
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> {
SizeAttribute(String val) : super('size', AttributeScope.INLINE, val);
SizeAttribute(String? val) : super('size', AttributeScope.INLINE, val);
}
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> {
ColorAttribute(String val) : super('color', AttributeScope.INLINE, val);
ColorAttribute(String? val) : super('color', AttributeScope.INLINE, val);
}
class BackgroundAttribute extends Attribute<String> {
BackgroundAttribute(String val)
BackgroundAttribute(String? val)
: super('background', AttributeScope.INLINE, val);
}
@ -235,19 +235,19 @@ class PlaceholderAttribute extends Attribute<bool> {
}
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> {
IndentAttribute({int level}) : super('indent', AttributeScope.BLOCK, level);
IndentAttribute({int? level}) : super('indent', AttributeScope.BLOCK, level);
}
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> {
ListAttribute(String val) : super('list', AttributeScope.BLOCK, val);
ListAttribute(String? val) : super('list', AttributeScope.BLOCK, val);
}
class CodeBlockAttribute extends Attribute<bool> {
@ -259,17 +259,17 @@ class BlockQuoteAttribute extends Attribute<bool> {
}
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> {
HeightAttribute(String val) : super('height', AttributeScope.IGNORE, val);
HeightAttribute(String? val) : super('height', AttributeScope.IGNORE, val);
}
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> {
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(data is String || data is Embeddable);
if (data is Embeddable) {
data = (data as Embeddable).toJson();
data = data.toJson();
} else if ((data as String).isEmpty) {
return Delta();
}
@ -89,7 +89,7 @@ class Document {
}
Delta format(int index, int len, Attribute attribute) {
assert(index >= 0 && len >= 0 && attribute != null);
assert(index >= 0 && len >= 0);
Delta delta = Delta();
@ -105,7 +105,7 @@ class Document {
Style collectStyle(int index, int len) {
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) {
@ -113,8 +113,8 @@ class Document {
if (res.node is Line) {
return res;
}
Block block = res.node;
return block.queryChild(res.offset, true);
Block block = (res.node as Block);
return block.queryChild(res.offset!, true);
}
compose(Delta delta, ChangeSource changeSource) {
@ -126,7 +126,7 @@ class Document {
delta = _transform(delta);
Delta originalDelta = toDelta();
for (Operation op in delta.toList()) {
Style style =
Style? style =
op.attributes != null ? Style.fromJson(op.attributes) : null;
if (op.isInsert) {
@ -205,7 +205,7 @@ class Document {
if (data is Embeddable) {
return data;
}
return Embeddable.fromJson(data);
return Embeddable.fromJson((data as Map<String, dynamic>));
}
close() {

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

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

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

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

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

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

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

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

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

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

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

@ -11,19 +11,16 @@ enum RuleType { INSERT, DELETE, FORMAT }
abstract class Rule {
const Rule();
Delta apply(Delta document, int index,
{int len, Object data, Attribute attribute}) {
assert(document != null);
assert(index != null);
validateArgs(len, data, attribute);
Delta? apply(Delta document, int index,
{int? len, Object? data, Attribute? attribute}) {
return applyRule(document, index,
len: len, data: data, attribute: attribute);
}
validateArgs(int len, Object data, Attribute attribute);
// validateArgs(int len, Object data, Attribute attribute);
Delta applyRule(Delta document, int index,
{int len, Object data, Attribute attribute});
Delta? applyRule(Delta document, int index,
{int? len, Object? data, Attribute? attribute});
RuleType get type;
}
@ -53,7 +50,7 @@ class Rules {
static Rules getInstance() => _instance;
Delta apply(RuleType ruleType, Document document, int index,
{int len, Object data, Attribute attribute}) {
{int? len, Object? data, Attribute? attribute}) {
final delta = document.toDelta();
for (var rule in _rules) {
if (rule.type != ruleType) {
@ -63,7 +60,7 @@ class Rules {
final result = rule.apply(delta, index,
len: len, data: data, attribute: attribute);
if (result != null) {
print("Rule $rule applied");
print("Rule $rule applied"); //made to here
return result..trim();
}
} 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);
int diff = 0;
while (userItr.hasNext || actualItr.hasNext) {
final length = math.min(userItr.peekLength(), actualItr.peekLength());
Operation userOperation = userItr.next(length);
Operation actualOperation = actualItr.next(length);
final int length =
math.min(userItr.peekLength(), actualItr.peekLength()) as int;
Operation userOperation = userItr.next(length)!;
Operation actualOperation = actualItr.next(length)!;
if (userOperation.length != actualOperation.length) {
throw ('userOp ' +
userOperation.length.toString() +

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Loading…
Cancel
Save