Browse Source

Upgraded to Flutter 1.12; fixed analyzer issues

Anatoly Pulyaevskiy 4 years ago
parent
commit
1615569a7b
33 changed files with 297 additions and 207 deletions
  1. 1
    0
      .gitignore
  2. 6
    6
      packages/notus/lib/src/convert/markdown.dart
  3. 8
    8
      packages/notus/lib/src/document.dart
  4. 7
    1
      packages/notus/lib/src/document/attributes.dart
  5. 4
    4
      packages/notus/lib/src/document/block.dart
  6. 9
    9
      packages/notus/lib/src/document/leaf.dart
  7. 18
    18
      packages/notus/lib/src/document/line.dart
  8. 10
    10
      packages/notus/lib/src/document/node.dart
  9. 12
    12
      packages/notus/lib/src/heuristics/delete_rules.dart
  10. 15
    15
      packages/notus/lib/src/heuristics/format_rules.dart
  11. 19
    15
      packages/notus/lib/src/heuristics/insert_rules.dart
  12. 3
    3
      packages/notus/pubspec.yaml
  13. 10
    7
      packages/notus/test/convert/markdown_test.dart
  14. 5
    5
      packages/notus/test/document/block_test.dart
  15. 13
    13
      packages/notus/test/document/line_test.dart
  16. 3
    3
      packages/notus/test/document/node_test.dart
  17. 23
    22
      packages/notus/test/document_test.dart
  18. 1
    1
      packages/notus/test/heuristics_test.dart
  19. 1
    0
      packages/zefyr/.gitignore
  20. 7
    0
      packages/zefyr/CHANGELOG.md
  21. 18
    0
      packages/zefyr/example/ios/Flutter/Flutter.podspec
  22. 58
    34
      packages/zefyr/example/ios/Podfile
  23. 23
    5
      packages/zefyr/example/ios/Podfile.lock
  24. 0
    3
      packages/zefyr/example/ios/Runner.xcodeproj/project.pbxproj
  25. 0
    1
      packages/zefyr/lib/src/widgets/buttons.dart
  26. 3
    3
      packages/zefyr/lib/src/widgets/controller.dart
  27. 10
    0
      packages/zefyr/lib/src/widgets/input.dart
  28. 1
    1
      packages/zefyr/lib/src/widgets/scaffold.dart
  29. 1
    1
      packages/zefyr/lib/src/widgets/scope.dart
  30. 2
    1
      packages/zefyr/lib/src/widgets/theme.dart
  31. 1
    1
      packages/zefyr/lib/src/widgets/toolbar.dart
  32. 2
    2
      packages/zefyr/pubspec.yaml
  33. 3
    3
      packages/zefyr/test/widgets/controller_test.dart

+ 1
- 0
.gitignore View File

@@ -1,2 +1,3 @@
1 1
 .DS_Store
2 2
 .idea/
3
+.dart_tool/

+ 6
- 6
packages/notus/lib/src/convert/markdown.dart View File

@@ -4,8 +4,8 @@
4 4
 
5 5
 import 'dart:convert';
6 6
 
7
-import 'package:quill_delta/quill_delta.dart';
8 7
 import 'package:notus/notus.dart';
8
+import 'package:quill_delta/quill_delta.dart';
9 9
 
10 10
 class NotusMarkdownCodec extends Codec<Delta, String> {
11 11
   const NotusMarkdownCodec();
@@ -33,8 +33,8 @@ class _NotusMarkdownEncoder extends Converter<Delta, String> {
33 33
     final buffer = StringBuffer();
34 34
     final lineBuffer = StringBuffer();
35 35
     NotusAttribute<String> currentBlockStyle;
36
-    NotusStyle currentInlineStyle = NotusStyle();
37
-    List<String> currentBlockLines = [];
36
+    var currentInlineStyle = NotusStyle();
37
+    var currentBlockLines = [];
38 38
 
39 39
     void _handleBlock(NotusAttribute<String> blockStyle) {
40 40
       if (currentBlockLines.isEmpty) {
@@ -86,7 +86,7 @@ class _NotusMarkdownEncoder extends Converter<Delta, String> {
86 86
       if (lf == -1) {
87 87
         _handleSpan(op.data, op.attributes);
88 88
       } else {
89
-        StringBuffer span = StringBuffer();
89
+        var span = StringBuffer();
90 90
         for (var i = 0; i < op.data.length; i++) {
91 91
           if (op.data.codeUnitAt(i) == 0x0A) {
92 92
             if (span.isNotEmpty) {
@@ -112,7 +112,7 @@ class _NotusMarkdownEncoder extends Converter<Delta, String> {
112 112
   }
113 113
 
114 114
   String _writeLine(String text, NotusStyle style) {
115
-    StringBuffer buffer = StringBuffer();
115
+    var buffer = StringBuffer();
116 116
     if (style.contains(NotusAttribute.heading)) {
117 117
       _writeAttribute(buffer, style.get<int>(NotusAttribute.heading));
118 118
     }
@@ -123,7 +123,7 @@ class _NotusMarkdownEncoder extends Converter<Delta, String> {
123 123
   }
124 124
 
125 125
   String _trimRight(StringBuffer buffer) {
126
-    String text = buffer.toString();
126
+    var text = buffer.toString();
127 127
     if (!text.endsWith(' ')) return '';
128 128
     final result = text.trimRight();
129 129
     buffer.clear();

+ 8
- 8
packages/notus/lib/src/document.dart View File

@@ -136,7 +136,7 @@ class NotusDocument {
136 136
   Delta replace(int index, int length, String text) {
137 137
     assert(index >= 0 && (text.isNotEmpty || length > 0),
138 138
         'With index $index, length $length and text "$text"');
139
-    Delta delta = Delta();
139
+    var delta = Delta();
140 140
     // We have to compose before applying delete rules
141 141
     // Otherwise delete would be operating on stale document snapshot.
142 142
     if (text.isNotEmpty) {
@@ -162,7 +162,7 @@ class NotusDocument {
162 162
   Delta format(int index, int length, NotusAttribute attribute) {
163 163
     assert(index >= 0 && length >= 0 && attribute != null);
164 164
 
165
-    Delta change = Delta();
165
+    var change = Delta();
166 166
 
167 167
     if (attribute is EmbedAttribute && length > 0) {
168 168
       // Must delete selected length of text before applying embed attribute
@@ -222,9 +222,9 @@ class NotusDocument {
222 222
     change.trim();
223 223
     assert(change.isNotEmpty);
224 224
 
225
-    int offset = 0;
225
+    var offset = 0;
226 226
     final before = toDelta();
227
-    for (final Operation op in change.toList()) {
227
+    for (final op in change.toList()) {
228 228
       final attributes =
229 229
           op.attributes != null ? NotusStyle.fromJson(op.attributes) : null;
230 230
       if (op.isInsert) {
@@ -272,21 +272,21 @@ class NotusDocument {
272 272
   void _loadDocument(Delta doc) {
273 273
     assert(doc.last.data.endsWith('\n'),
274 274
         'Invalid document delta. Document delta must always end with a line-break.');
275
-    int offset = 0;
276
-    for (final Operation op in doc.toList()) {
275
+    var offset = 0;
276
+    for (final op in doc.toList()) {
277 277
       final style =
278 278
           op.attributes != null ? NotusStyle.fromJson(op.attributes) : null;
279 279
       if (op.isInsert) {
280 280
         _root.insert(offset, op.data, style);
281 281
       } else {
282 282
         throw ArgumentError.value(doc,
283
-            "Document Delta can only contain insert operations but ${op.key} found.");
283
+            'Document Delta can only contain insert operations but ${op.key} found.');
284 284
       }
285 285
       offset += op.length;
286 286
     }
287 287
     // Must remove last line if it's empty and with no styles.
288 288
     // TODO: find a way for DocumentRoot to not create extra line when composing initial delta.
289
-    Node node = _root.last;
289
+    final node = _root.last;
290 290
     if (node is LineNode &&
291 291
         node.parent is! BlockNode &&
292 292
         node.style.isEmpty &&

+ 7
- 1
packages/notus/lib/src/document/attributes.dart View File

@@ -38,6 +38,7 @@ abstract class NotusAttributeKey<T> {
38 38
 abstract class NotusAttributeBuilder<T> implements NotusAttributeKey<T> {
39 39
   const NotusAttributeBuilder._(this.key, this.scope);
40 40
 
41
+  @override
41 42
   final String key;
42 43
   final NotusAttributeScope scope;
43 44
   NotusAttribute<T> get unset => NotusAttribute<T>._(key, scope, null);
@@ -138,9 +139,11 @@ class NotusAttribute<T> implements NotusAttributeBuilder<T> {
138 139
   const NotusAttribute._(this.key, this.scope, this.value);
139 140
 
140 141
   /// Unique key of this attribute.
142
+  @override
141 143
   final String key;
142 144
 
143 145
   /// Scope of this attribute.
146
+  @override
144 147
   final NotusAttributeScope scope;
145 148
 
146 149
   /// Value of this attribute.
@@ -159,6 +162,7 @@ class NotusAttribute<T> implements NotusAttributeBuilder<T> {
159 162
   ///
160 163
   /// When composed into a rich text document, unset attributes remove
161 164
   /// associated style.
165
+  @override
162 166
   NotusAttribute<T> get unset => NotusAttribute<T>._(key, scope, null);
163 167
 
164 168
   /// Returns `true` if this attribute is an unset attribute.
@@ -167,6 +171,7 @@ class NotusAttribute<T> implements NotusAttributeBuilder<T> {
167 171
   /// Returns `true` if this is an inline-scoped attribute.
168 172
   bool get isInline => scope == NotusAttributeScope.inline;
169 173
 
174
+  @override
170 175
   NotusAttribute<T> withValue(T value) =>
171 176
       NotusAttribute<T>._(key, scope, value);
172 177
 
@@ -205,7 +210,7 @@ class NotusStyle {
205 210
     return NotusStyle._(result);
206 211
   }
207 212
 
208
-  NotusStyle() : _data = Map<String, NotusAttribute>();
213
+  NotusStyle() : _data = <String, NotusAttribute>{};
209 214
 
210 215
   /// Returns `true` if this attribute set is empty.
211 216
   bool get isEmpty => _data.isEmpty;
@@ -398,6 +403,7 @@ class EmbedAttributeBuilder
398 403
   @override
399 404
   NotusAttribute<Map<String, dynamic>> get unset => EmbedAttribute._(null);
400 405
 
406
+  @override
401 407
   NotusAttribute<Map<String, dynamic>> withValue(Map<String, dynamic> value) =>
402 408
       EmbedAttribute._(value);
403 409
 }

+ 4
- 4
packages/notus/lib/src/document/block.dart View File

@@ -33,14 +33,14 @@ class BlockNode extends ContainerNode<LineNode>
33 33
       insertAfter(line);
34 34
     } else {
35 35
       /// need to split this block into two as [line] is in the middle.
36
-      BlockNode before = clone();
36
+      final before = clone();
37 37
       insertBefore(before);
38 38
 
39
-      LineNode child = this.first;
39
+      LineNode child = first;
40 40
       while (child != line) {
41 41
         child.unlink();
42 42
         before.add(child);
43
-        child = this.first as LineNode;
43
+        child = first as LineNode;
44 44
       }
45 45
       line.unlink();
46 46
       insertBefore(line);
@@ -74,7 +74,7 @@ class BlockNode extends ContainerNode<LineNode>
74 74
   @override
75 75
   void optimize() {
76 76
     if (isEmpty) {
77
-      Node sibling = this.previous;
77
+      final sibling = previous;
78 78
       unlink();
79 79
       if (sibling != null) sibling.optimize();
80 80
       return;

+ 9
- 9
packages/notus/lib/src/document/leaf.dart View File

@@ -54,7 +54,7 @@ abstract class LeafNode extends Node
54 54
     if (index == length && isLast) return null;
55 55
     if (index == length && !isLast) return next as LeafNode;
56 56
 
57
-    String text = _value;
57
+    final text = _value;
58 58
     _value = text.substring(0, index);
59 59
     final split = LeafNode(text.substring(index));
60 60
     split.applyStyle(style);
@@ -69,7 +69,7 @@ abstract class LeafNode extends Node
69 69
   /// method may return `null`.
70 70
   LeafNode cutAt(int index) {
71 71
     assert(index >= 0 && index <= length);
72
-    LeafNode cut = splitAt(index);
72
+    final cut = splitAt(index);
73 73
     cut?.unlink();
74 74
     return cut;
75 75
   }
@@ -88,7 +88,7 @@ abstract class LeafNode extends Node
88 88
         'Actual node length: ${this.length}.');
89 89
     // Since `index < this.length` (guarded by assert) below line
90 90
     // always returns a new node.
91
-    LeafNode target = splitAt(index);
91
+    final target = splitAt(index);
92 92
     target.splitAt(length);
93 93
     return target;
94 94
   }
@@ -104,7 +104,7 @@ abstract class LeafNode extends Node
104 104
   @override
105 105
   void applyStyle(NotusStyle value) {
106 106
     assert(value != null && (value.isInline || value.isEmpty),
107
-        "Style cannot be applied to this leaf node: $value");
107
+        'Style cannot be applied to this leaf node: $value');
108 108
     assert(() {
109 109
       if (value.contains(NotusAttribute.embed)) {
110 110
         if (value.get(NotusAttribute.embed) == NotusAttribute.embed.unset) {
@@ -157,7 +157,7 @@ abstract class LeafNode extends Node
157 157
     final local = math.min(this.length - index, length);
158 158
     final node = isolate(index, local);
159 159
 
160
-    int remaining = length - local;
160
+    final remaining = length - local;
161 161
     if (remaining > 0) {
162 162
       assert(node.next != null);
163 163
       node.next.retain(0, remaining, style);
@@ -177,7 +177,7 @@ abstract class LeafNode extends Node
177 177
     final actualNext = target.next;
178 178
     target.unlink();
179 179
 
180
-    int remaining = length - local;
180
+    final remaining = length - local;
181 181
     if (remaining > 0) {
182 182
       assert(actualNext != null);
183 183
       actualNext.delete(0, remaining);
@@ -189,15 +189,15 @@ abstract class LeafNode extends Node
189 189
   @override
190 190
   String toString() {
191 191
     final keys = style.keys.toList(growable: false)..sort();
192
-    String styleKeys = keys.join();
193
-    return "⟨$value⟩$styleKeys";
192
+    final styleKeys = keys.join();
193
+    return '⟨$value⟩$styleKeys';
194 194
   }
195 195
 
196 196
   /// Optimizes this text node by merging it with adjacent nodes if they share
197 197
   /// the same style.
198 198
   @override
199 199
   void optimize() {
200
-    LeafNode node = this;
200
+    var node = this;
201 201
     if (!node.isFirst) {
202 202
       LeafNode mergeWith = node.previous;
203 203
       if (mergeWith.style == node.style) {

+ 18
- 18
packages/notus/lib/src/document/line.dart View File

@@ -59,15 +59,15 @@ class LineNode extends ContainerNode<LeafNode>
59 59
   /// This is an equivalent of inserting a line-break character at [index].
60 60
   LineNode splitAt(int index) {
61 61
     assert(index == 0 || (index > 0 && index < length),
62
-        'Index is out of bounds. Index: $index. Actual node length: ${this.length}.');
62
+        'Index is out of bounds. Index: $index. Actual node length: ${length}.');
63 63
 
64
-    LineNode line = clone();
64
+    final line = clone();
65 65
     insertAfter(line);
66 66
     if (index == length - 1) return line;
67 67
 
68 68
     final split = lookup(index);
69 69
     while (!split.node.isLast) {
70
-      LeafNode child = this.last;
70
+      LeafNode child = last;
71 71
       child.unlink();
72 72
       line.addFirst(child);
73 73
     }
@@ -106,10 +106,10 @@ class LineNode extends ContainerNode<LeafNode>
106 106
   /// - inline attribute X is included in the result only if it exists
107 107
   ///   for every character within this range (line-break characters excluded).
108 108
   NotusStyle collectStyle(int offset, int length) {
109
-    int local = math.min(this.length - offset, length);
109
+    final local = math.min(this.length - offset, length);
110 110
 
111
-    NotusStyle result = NotusStyle();
112
-    Set<NotusAttribute> excluded = Set();
111
+    var result = NotusStyle();
112
+    final excluded = <NotusAttribute>{};
113 113
 
114 114
     void _handle(NotusStyle style) {
115 115
       if (result.isEmpty) {
@@ -130,7 +130,7 @@ class LineNode extends ContainerNode<LeafNode>
130 130
     LeafNode node = data.node;
131 131
     if (node != null) {
132 132
       result = result.mergeAll(node.style);
133
-      int pos = node.length - data.offset;
133
+      var pos = node.length - data.offset;
134 134
       while (!node.isLast && pos < local) {
135 135
         node = node.next as LeafNode;
136 136
         _handle(node.style);
@@ -138,13 +138,13 @@ class LineNode extends ContainerNode<LeafNode>
138 138
       }
139 139
     }
140 140
 
141
-    result = result.mergeAll(this.style);
141
+    result = result.mergeAll(style);
142 142
     if (parent is BlockNode) {
143 143
       BlockNode block = parent;
144 144
       result = result.mergeAll(block.style);
145 145
     }
146 146
 
147
-    int remaining = length - local;
147
+    final remaining = length - local;
148 148
     if (remaining > 0) {
149 149
       final rest = nextLine.collectStyle(0, remaining);
150 150
       _handle(rest);
@@ -162,7 +162,7 @@ class LineNode extends ContainerNode<LeafNode>
162 162
 
163 163
   @override
164 164
   Delta toDelta() {
165
-    final Delta delta = children
165
+    final delta = children
166 166
         .map((text) => text.toDelta())
167 167
         .fold(Delta(), (a, b) => a.concat(b));
168 168
     var attributes = style;
@@ -220,11 +220,11 @@ class LineNode extends ContainerNode<LeafNode>
220 220
   @override
221 221
   void retain(int index, int length, NotusStyle style) {
222 222
     if (style == null) return;
223
-    int thisLength = this.length;
223
+    final thisLength = this.length;
224 224
 
225 225
     final local = math.min(thisLength - index, length);
226 226
     // If index is at line-break character this is line/block format update.
227
-    bool isLineFormat = (index + local == thisLength) && local == 1;
227
+    final isLineFormat = (index + local == thisLength) && local == 1;
228 228
 
229 229
     if (isLineFormat) {
230 230
       assert(
@@ -240,7 +240,7 @@ class LineNode extends ContainerNode<LeafNode>
240 240
       super.retain(index, local, style);
241 241
     }
242 242
 
243
-    int remaining = length - local;
243
+    final remaining = length - local;
244 244
     if (remaining > 0) {
245 245
       assert(nextLine != null);
246 246
       nextLine.retain(0, remaining, style);
@@ -250,7 +250,7 @@ class LineNode extends ContainerNode<LeafNode>
250 250
   @override
251 251
   void delete(int index, int length) {
252 252
     final local = math.min(this.length - index, length);
253
-    bool isLFDeleted = (index + local == this.length);
253
+    final isLFDeleted = (index + local == this.length);
254 254
     if (isLFDeleted) {
255 255
       // Our line-break deleted with all style information.
256 256
       clearStyle();
@@ -262,7 +262,7 @@ class LineNode extends ContainerNode<LeafNode>
262 262
       super.delete(index, local);
263 263
     }
264 264
 
265
-    int remaining = length - local;
265
+    final remaining = length - local;
266 266
     if (remaining > 0) {
267 267
       assert(nextLine != null);
268 268
       nextLine.delete(0, remaining);
@@ -305,14 +305,14 @@ class LineNode extends ContainerNode<LeafNode>
305 305
         unwrap();
306 306
       } else if (blockStyle != parentStyle) {
307 307
         unwrap();
308
-        BlockNode block = BlockNode();
308
+        final block = BlockNode();
309 309
         block.applyAttribute(blockStyle);
310 310
         wrap(block);
311 311
         block.optimize();
312 312
       } // else the same style, no-op.
313 313
     } else if (blockStyle != NotusAttribute.block.unset) {
314 314
       // Only wrap with a new block if this is not an unset
315
-      BlockNode block = BlockNode();
315
+      final block = BlockNode();
316 316
       block.applyAttribute(blockStyle);
317 317
       wrap(block);
318 318
       block.optimize();
@@ -329,7 +329,7 @@ class LineNode extends ContainerNode<LeafNode>
329 329
       add(child);
330 330
       child.formatAndOptimize(style);
331 331
     } else {
332
-      final LookupResult result = lookup(index, inclusive: true);
332
+      final result = lookup(index, inclusive: true);
333 333
       result.node.insert(result.offset, text, style);
334 334
     }
335 335
   }

+ 10
- 10
packages/notus/lib/src/document/node.dart View File

@@ -42,8 +42,8 @@ abstract class Node extends LinkedListEntry<Node> {
42 42
   /// To get offset of this node in the document see [documentOffset].
43 43
   int get offset {
44 44
     if (isFirst) return 0;
45
-    int offset = 0;
46
-    Node node = this;
45
+    var offset = 0;
46
+    var node = this;
47 47
     do {
48 48
       node = node.previous;
49 49
       offset += node.length;
@@ -53,14 +53,14 @@ abstract class Node extends LinkedListEntry<Node> {
53 53
 
54 54
   /// Offset in characters of this node in the document.
55 55
   int get documentOffset {
56
-    int parentOffset = (_parent is! RootNode) ? _parent.documentOffset : 0;
57
-    return parentOffset + this.offset;
56
+    final parentOffset = (_parent is! RootNode) ? _parent.documentOffset : 0;
57
+    return parentOffset + offset;
58 58
   }
59 59
 
60 60
   /// Returns `true` if this node contains character at specified [offset] in
61 61
   /// the document.
62 62
   bool containsOffset(int offset) {
63
-    int o = documentOffset;
63
+    final o = documentOffset;
64 64
     return o <= offset && offset < o + length;
65 65
   }
66 66
 
@@ -208,10 +208,10 @@ abstract class ContainerNode<T extends Node> extends Node {
208 208
   /// which points at the same character position in the document as the
209 209
   /// original [offset].
210 210
   LookupResult lookup(int offset, {bool inclusive = false}) {
211
-    assert(offset >= 0 && offset <= this.length);
211
+    assert(offset >= 0 && offset <= length);
212 212
 
213
-    for (Node node in children) {
214
-      final int length = node.length;
213
+    for (final node in children) {
214
+      final length = node.length;
215 215
       if (offset < length || (inclusive && offset == length && (node.isLast))) {
216 216
         return LookupResult(node, offset);
217 217
       }
@@ -238,11 +238,11 @@ abstract class ContainerNode<T extends Node> extends Node {
238 238
 
239 239
     if (isEmpty) {
240 240
       assert(index == 0);
241
-      T node = defaultChild;
241
+      final node = defaultChild;
242 242
       add(node);
243 243
       node.insert(index, value, style);
244 244
     } else {
245
-      LookupResult result = lookup(index);
245
+      final result = lookup(index);
246 246
       result.node.insert(result.offset, value, style);
247 247
     }
248 248
   }

+ 12
- 12
packages/notus/lib/src/heuristics/delete_rules.dart View File

@@ -2,8 +2,8 @@
2 2
 // for details. All rights reserved. Use of this source code is governed by a
3 3
 // BSD-style license that can be found in the LICENSE file.
4 4
 
5
-import 'package:quill_delta/quill_delta.dart';
6 5
 import 'package:notus/notus.dart';
6
+import 'package:quill_delta/quill_delta.dart';
7 7
 
8 8
 /// A heuristic rule for delete operations.
9 9
 abstract class DeleteRule {
@@ -39,19 +39,19 @@ class PreserveLineStyleOnMergeRule extends DeleteRule {
39 39
 
40 40
   @override
41 41
   Delta apply(Delta document, int index, int length) {
42
-    DeltaIterator iter = DeltaIterator(document);
42
+    final iter = DeltaIterator(document);
43 43
     iter.skip(index);
44 44
     final target = iter.next(1);
45 45
     if (target.data != '\n') return null;
46 46
     iter.skip(length - 1);
47
-    final Delta result = Delta()
47
+    final result = Delta()
48 48
       ..retain(index)
49 49
       ..delete(length);
50 50
 
51 51
     // Look for next line-break to apply the attributes
52 52
     while (iter.hasNext) {
53 53
       final op = iter.next();
54
-      int lf = op.data.indexOf('\n');
54
+      final lf = op.data.indexOf('\n');
55 55
       if (lf == -1) {
56 56
         result..retain(op.length);
57 57
         continue;
@@ -80,18 +80,18 @@ class EnsureEmbedLineRule extends DeleteRule {
80 80
 
81 81
   @override
82 82
   Delta apply(Delta document, int index, int length) {
83
-    DeltaIterator iter = DeltaIterator(document);
83
+    final iter = DeltaIterator(document);
84 84
 
85 85
     // First, check if line-break deleted after an embed.
86
-    Operation op = iter.skip(index);
87
-    int indexDelta = 0;
88
-    int lengthDelta = 0;
89
-    int remaining = length;
90
-    bool foundEmbed = false;
91
-    bool hasLineBreakBefore = false;
86
+    var op = iter.skip(index);
87
+    var indexDelta = 0;
88
+    var lengthDelta = 0;
89
+    var remaining = length;
90
+    var foundEmbed = false;
91
+    var hasLineBreakBefore = false;
92 92
     if (op != null && op.data.endsWith(kZeroWidthSpace)) {
93 93
       foundEmbed = true;
94
-      Operation candidate = iter.next(1);
94
+      var candidate = iter.next(1);
95 95
       remaining--;
96 96
       if (candidate.data == '\n') {
97 97
         indexDelta += 1;

+ 15
- 15
packages/notus/lib/src/heuristics/format_rules.dart View File

@@ -2,8 +2,8 @@
2 2
 // for details. All rights reserved. Use of this source code is governed by a
3 3
 // BSD-style license that can be found in the LICENSE file.
4 4
 
5
-import 'package:quill_delta/quill_delta.dart';
6 5
 import 'package:notus/notus.dart';
6
+import 'package:quill_delta/quill_delta.dart';
7 7
 
8 8
 /// A heuristic rule for format (retain) operations.
9 9
 abstract class FormatRule {
@@ -24,13 +24,13 @@ class ResolveLineFormatRule extends FormatRule {
24 24
   Delta apply(Delta document, int index, int length, NotusAttribute attribute) {
25 25
     if (attribute.scope != NotusAttributeScope.line) return null;
26 26
 
27
-    Delta result = Delta()..retain(index);
27
+    var result = Delta()..retain(index);
28 28
     final iter = DeltaIterator(document);
29 29
     iter.skip(index);
30 30
 
31 31
     // Apply line styles to all line-break characters within range of this
32 32
     // retain operation.
33
-    int current = 0;
33
+    var current = 0;
34 34
     while (current < length && iter.hasNext) {
35 35
       final op = iter.next(length - current);
36 36
       if (op.data.contains('\n')) {
@@ -44,7 +44,7 @@ class ResolveLineFormatRule extends FormatRule {
44 44
     // And include extra line-break after retain
45 45
     while (iter.hasNext) {
46 46
       final op = iter.next();
47
-      int lf = op.data.indexOf('\n');
47
+      final lf = op.data.indexOf('\n');
48 48
       if (lf == -1) {
49 49
         result..retain(op.length);
50 50
         continue;
@@ -57,8 +57,8 @@ class ResolveLineFormatRule extends FormatRule {
57 57
 
58 58
   Delta _applyAttribute(String text, NotusAttribute attribute) {
59 59
     final result = Delta();
60
-    int offset = 0;
61
-    int lf = text.indexOf('\n');
60
+    var offset = 0;
61
+    var lf = text.indexOf('\n');
62 62
     while (lf >= 0) {
63 63
       result..retain(lf - offset)..retain(1, attribute.toJson());
64 64
       offset = lf + 1;
@@ -79,18 +79,18 @@ class ResolveInlineFormatRule extends FormatRule {
79 79
   Delta apply(Delta document, int index, int length, NotusAttribute attribute) {
80 80
     if (attribute.scope != NotusAttributeScope.inline) return null;
81 81
 
82
-    Delta result = Delta()..retain(index);
82
+    final result = Delta()..retain(index);
83 83
     final iter = DeltaIterator(document);
84 84
     iter.skip(index);
85 85
 
86 86
     // Apply inline styles to all non-line-break characters within range of this
87 87
     // retain operation.
88
-    int current = 0;
88
+    var current = 0;
89 89
     while (current < length && iter.hasNext) {
90 90
       final op = iter.next(length - current);
91
-      int lf = op.data.indexOf('\n');
91
+      var lf = op.data.indexOf('\n');
92 92
       if (lf != -1) {
93
-        int pos = 0;
93
+        var pos = 0;
94 94
         while (lf != -1) {
95 95
           result..retain(lf - pos, attribute.toJson())..retain(1);
96 96
           pos = lf + 1;
@@ -122,12 +122,12 @@ class FormatLinkAtCaretPositionRule extends FormatRule {
122 122
     // edge cases.
123 123
     if (length != 0) return null;
124 124
 
125
-    Delta result = Delta();
125
+    final result = Delta();
126 126
     final iter = DeltaIterator(document);
127 127
     final before = iter.skip(index);
128 128
     final after = iter.next();
129
-    int startIndex = index;
130
-    int retain = 0;
129
+    var startIndex = index;
130
+    var retain = 0;
131 131
     if (before != null && before.hasAttribute(attribute.key)) {
132 132
       startIndex -= before.length;
133 133
       retain = before.length;
@@ -171,7 +171,7 @@ class FormatEmbedsRule extends FormatRule {
171 171
 
172 172
   Delta _insertEmbed(
173 173
       Delta document, int index, int length, EmbedAttribute embed) {
174
-    Delta result = Delta()..retain(index);
174
+    final result = Delta()..retain(index);
175 175
     final iter = DeltaIterator(document);
176 176
     final previous = iter.skip(index);
177 177
     iter.skip(length); // ignore deleted part.
@@ -207,7 +207,7 @@ class FormatEmbedsRule extends FormatRule {
207 207
     Map<String, dynamic> attributes;
208 208
     while (iterator.hasNext) {
209 209
       final op = iterator.next();
210
-      int lf = op.data.indexOf('\n');
210
+      final lf = op.data.indexOf('\n');
211 211
       if (lf >= 0) {
212 212
         attributes = op.attributes;
213 213
         break;

+ 19
- 15
packages/notus/lib/src/heuristics/insert_rules.dart View File

@@ -2,8 +2,8 @@
2 2
 // for details. All rights reserved. Use of this source code is governed by a
3 3
 // BSD-style license that can be found in the LICENSE file.
4 4
 
5
-import 'package:quill_delta/quill_delta.dart';
6 5
 import 'package:notus/notus.dart';
6
+import 'package:quill_delta/quill_delta.dart';
7 7
 
8 8
 /// A heuristic rule for insert operations.
9 9
 abstract class InsertRule {
@@ -43,11 +43,11 @@ class PreserveLineStyleOnSplitRule extends InsertRule {
43 43
   Delta apply(Delta document, int index, String text) {
44 44
     if (text != '\n') return null;
45 45
 
46
-    DeltaIterator iter = DeltaIterator(document);
46
+    final iter = DeltaIterator(document);
47 47
     final before = iter.skip(index);
48 48
     final after = iter.next();
49 49
     if (isEdgeLineSplit(before, after)) return null;
50
-    Delta result = Delta()..retain(index);
50
+    final result = Delta()..retain(index);
51 51
     if (after.data.contains('\n')) {
52 52
       // It is not allowed to combine line and inline styles in insert
53 53
       // operation containing line-break together with other characters.
@@ -61,7 +61,7 @@ class PreserveLineStyleOnSplitRule extends InsertRule {
61 61
     Map<String, dynamic> attributes;
62 62
     while (iter.hasNext) {
63 63
       final op = iter.next();
64
-      int lf = op.data.indexOf('\n');
64
+      final lf = op.data.indexOf('\n');
65 65
       if (lf >= 0) {
66 66
         attributes = op.attributes;
67 67
         break;
@@ -82,7 +82,7 @@ class ResetLineFormatOnNewLineRule extends InsertRule {
82 82
   Delta apply(Delta document, int index, String text) {
83 83
     if (text != '\n') return null;
84 84
 
85
-    DeltaIterator iter = DeltaIterator(document);
85
+    final iter = DeltaIterator(document);
86 86
     iter.skip(index);
87 87
     final target = iter.next();
88 88
 
@@ -117,7 +117,7 @@ class AutoExitBlockRule extends InsertRule {
117 117
   Delta apply(Delta document, int index, String text) {
118 118
     if (text != '\n') return null;
119 119
 
120
-    DeltaIterator iter = DeltaIterator(document);
120
+    final iter = DeltaIterator(document);
121 121
     final previous = iter.skip(index);
122 122
     final target = iter.next();
123 123
     final isInBlock = target.isNotPlain &&
@@ -126,8 +126,12 @@ class AutoExitBlockRule extends InsertRule {
126 126
       // We reset block style even if this line is not the last one in it's
127 127
       // block which effectively splits the block into two.
128 128
       // TODO: For code blocks this should not split the block but allow inserting as many lines as needed.
129
-      var attributes =
130
-          target.attributes != null ? target.attributes : <String, dynamic>{};
129
+      var attributes;
130
+      if (target.attributes != null) {
131
+        attributes = target.attributes;
132
+      } else {
133
+        attributes = <String, dynamic>{};
134
+      }
131 135
       attributes.addAll(NotusAttribute.block.unset.toJson());
132 136
       return Delta()..retain(index)..retain(1, attributes);
133 137
     }
@@ -144,7 +148,7 @@ class PreserveInlineStylesRule extends InsertRule {
144 148
     // This rule is only applicable to characters other than line-break.
145 149
     if (text.contains('\n')) return null;
146 150
 
147
-    DeltaIterator iter = DeltaIterator(document);
151
+    final iter = DeltaIterator(document);
148 152
     final previous = iter.skip(index);
149 153
     // If there is a line-break in previous chunk, there should be no inline
150 154
     // styles. Also if there is no previous operation we are at the beginning
@@ -200,7 +204,7 @@ class AutoFormatLinksRule extends InsertRule {
200 204
     // everything else.
201 205
     if (text != ' ') return null;
202 206
 
203
-    DeltaIterator iter = DeltaIterator(document);
207
+    final iter = DeltaIterator(document);
204 208
     final previous = iter.skip(index);
205 209
     // No previous operation means no link.
206 210
     if (previous == null) return null;
@@ -239,7 +243,7 @@ class ForceNewlineForInsertsAroundEmbedRule extends InsertRule {
239 243
 
240 244
   @override
241 245
   Delta apply(Delta document, int index, String text) {
242
-    DeltaIterator iter = DeltaIterator(document);
246
+    final iter = DeltaIterator(document);
243 247
     final previous = iter.skip(index);
244 248
     final target = iter.next();
245 249
     final beforeEmbed = target.data == EmbedNode.kPlainTextPlaceholder;
@@ -276,14 +280,14 @@ class PreserveBlockStyleOnPasteRule extends InsertRule {
276 280
       return null;
277 281
     }
278 282
 
279
-    DeltaIterator iter = DeltaIterator(document);
283
+    final iter = DeltaIterator(document);
280 284
     iter.skip(index);
281 285
 
282 286
     // Look for next line-break.
283 287
     Map<String, dynamic> lineStyle;
284 288
     while (iter.hasNext) {
285 289
       final op = iter.next();
286
-      int lf = op.data.indexOf('\n');
290
+      final lf = op.data.indexOf('\n');
287 291
       if (lf >= 0) {
288 292
         lineStyle = op.attributes;
289 293
         break;
@@ -305,8 +309,8 @@ class PreserveBlockStyleOnPasteRule extends InsertRule {
305 309
     }
306 310
 
307 311
     final lines = text.split('\n');
308
-    Delta result = Delta()..retain(index);
309
-    for (int i = 0; i < lines.length; i++) {
312
+    final result = Delta()..retain(index);
313
+    for (var i = 0; i < lines.length; i++) {
310 314
       final line = lines[i];
311 315
       if (line.isNotEmpty) {
312 316
         result.insert(line);

+ 3
- 3
packages/notus/pubspec.yaml View File

@@ -5,7 +5,7 @@ author: Anatoly Pulyaevskiy <anatoly.pulyaevskiy@gmail.com>
5 5
 homepage: https://github.com/memspace/zefyr
6 6
 
7 7
 environment:
8
-  sdk: '>=2.0.0 <3.0.0'
8
+  sdk: '>=2.2.0 <3.0.0'
9 9
 
10 10
 dependencies:
11 11
   collection: ^1.14.6
@@ -15,5 +15,5 @@ dependencies:
15 15
 
16 16
 dev_dependencies:
17 17
   pedantic: ^1.0.0
18
-  test: ^1.0.0
19
-  test_coverage: ^0.2.1
18
+  test: ^1.10.0
19
+  test_coverage: ^0.4.0

+ 10
- 7
packages/notus/test/convert/markdown_test.dart View File

@@ -3,10 +3,10 @@
3 3
 // BSD-style license that can be found in the LICENSE file.
4 4
 import 'dart:convert';
5 5
 
6
-import 'package:test/test.dart';
7
-import 'package:quill_delta/quill_delta.dart';
8
-import 'package:notus/notus.dart';
9 6
 import 'package:notus/convert.dart';
7
+import 'package:notus/notus.dart';
8
+import 'package:quill_delta/quill_delta.dart';
9
+import 'package:test/test.dart';
10 10
 
11 11
 void main() {
12 12
   group('$NotusMarkdownCodec.encode', () {
@@ -25,7 +25,7 @@ void main() {
25 25
     });
26 26
 
27 27
     test('bold italic', () {
28
-      runFor(NotusAttribute<bool> attribute, String expected) {
28
+      void runFor(NotusAttribute<bool> attribute, String expected) {
29 29
         final delta = Delta()
30 30
           ..insert('This ')
31 31
           ..insert('house', attribute.toJson())
@@ -87,7 +87,8 @@ void main() {
87 87
     });
88 88
 
89 89
     test('heading styles', () {
90
-      runFor(NotusAttribute<int> attribute, String source, String expected) {
90
+      void runFor(
91
+          NotusAttribute<int> attribute, String source, String expected) {
91 92
         final delta = Delta()..insert(source)..insert('\n', attribute.toJson());
92 93
         final result = notusMarkdown.encode(delta);
93 94
         expect(result, expected);
@@ -99,7 +100,8 @@ void main() {
99 100
     });
100 101
 
101 102
     test('block styles', () {
102
-      runFor(NotusAttribute<String> attribute, String source, String expected) {
103
+      void runFor(
104
+          NotusAttribute<String> attribute, String source, String expected) {
103 105
         final delta = Delta()..insert(source)..insert('\n', attribute.toJson());
104 106
         final result = notusMarkdown.encode(delta);
105 107
         expect(result, expected);
@@ -112,7 +114,8 @@ void main() {
112 114
     });
113 115
 
114 116
     test('multiline blocks', () {
115
-      runFor(NotusAttribute<String> attribute, String source, String expected) {
117
+      void runFor(
118
+          NotusAttribute<String> attribute, String source, String expected) {
116 119
         final delta = Delta()
117 120
           ..insert(source)
118 121
           ..insert('\n', attribute.toJson())

+ 5
- 5
packages/notus/test/document/block_test.dart View File

@@ -2,8 +2,8 @@
2 2
 // for details. All rights reserved. Use of this source code is governed by a
3 3
 // BSD-style license that can be found in the LICENSE file.
4 4
 import 'package:notus/notus.dart';
5
-import 'package:test/test.dart';
6 5
 import 'package:quill_delta/quill_delta.dart';
6
+import 'package:test/test.dart';
7 7
 
8 8
 final ulAttrs = NotusStyle().merge(NotusAttribute.ul);
9 9
 final olAttrs = NotusStyle().merge(NotusAttribute.ol);
@@ -17,16 +17,16 @@ void main() {
17 17
     });
18 18
 
19 19
     test('empty', () {
20
-      BlockNode node = BlockNode();
20
+      final node = BlockNode();
21 21
       expect(node, isEmpty);
22 22
       expect(node.length, 0);
23 23
       expect(node.style, NotusStyle());
24 24
     });
25 25
 
26 26
     test('toString', () {
27
-      LineNode line = LineNode();
27
+      final line = LineNode();
28 28
       line.add(TextNode('London "Grammar"'));
29
-      BlockNode block = BlockNode();
29
+      final block = BlockNode();
30 30
       block.applyAttribute(NotusAttribute.ul);
31 31
       block.add(line);
32 32
       final expected = '§ {ul}\n  └ ¶ ⟨London "Grammar"⟩ ⏎';
@@ -59,7 +59,7 @@ void main() {
59 59
       expect(block.first, const TypeMatcher<LineNode>());
60 60
 
61 61
       LineNode line = block.first;
62
-      Delta delta = Delta()
62
+      final delta = Delta()
63 63
         ..insert('Hello world')
64 64
         ..insert('\n', ulAttrs.toJson());
65 65
       expect(line.toDelta(), delta);

+ 13
- 13
packages/notus/test/document/line_test.dart View File

@@ -1,9 +1,9 @@
1 1
 // Copyright (c) 2018, the Zefyr project authors.  Please see the AUTHORS file
2 2
 // for details. All rights reserved. Use of this source code is governed by a
3 3
 // BSD-style license that can be found in the LICENSE file.
4
-import 'package:test/test.dart';
5
-import 'package:quill_delta/quill_delta.dart';
6 4
 import 'package:notus/notus.dart';
5
+import 'package:quill_delta/quill_delta.dart';
6
+import 'package:test/test.dart';
7 7
 
8 8
 final boldStyle = NotusStyle().merge(NotusAttribute.bold);
9 9
 final h1Style = NotusStyle().merge(NotusAttribute.h1);
@@ -19,7 +19,7 @@ void main() {
19 19
     });
20 20
 
21 21
     test('empty', () {
22
-      LineNode node = LineNode();
22
+      final node = LineNode();
23 23
       expect(node, isEmpty);
24 24
       expect(node.length, 1);
25 25
       expect(node.style, NotusStyle());
@@ -27,7 +27,7 @@ void main() {
27 27
     });
28 28
 
29 29
     test('hasEmbed', () {
30
-      LineNode node = LineNode();
30
+      final node = LineNode();
31 31
       expect(node.hasEmbed, isFalse);
32 32
       node.add(EmbedNode());
33 33
       expect(node.hasEmbed, isTrue);
@@ -50,7 +50,7 @@ void main() {
50 50
     });
51 51
 
52 52
     test('toString', () {
53
-      LineNode node = LineNode();
53
+      final node = LineNode();
54 54
       node.insert(0, 'London "Grammar" - Hey Now', null);
55 55
       node.retain(0, 16, boldStyle);
56 56
       node.applyAttribute(NotusAttribute.h1);
@@ -68,14 +68,14 @@ void main() {
68 68
     });
69 69
 
70 70
     test('insert into empty line', () {
71
-      LineNode node = LineNode();
71
+      final node = LineNode();
72 72
       node.insert(0, 'London "Grammar" - Hey Now', null);
73 73
       expect(node, hasLength(27));
74 74
       expect(node.toDelta(), Delta()..insert('London "Grammar" - Hey Now\n'));
75 75
     });
76 76
 
77 77
     test('insert into empty line with styles', () {
78
-      LineNode node = LineNode();
78
+      final node = LineNode();
79 79
       node.insert(0, 'London "Grammar" - Hey Now', null);
80 80
       node.retain(0, 16, boldStyle);
81 81
       node.applyAttribute(NotusAttribute.h1);
@@ -90,7 +90,7 @@ void main() {
90 90
     });
91 91
 
92 92
     test('insert into non-empty line', () {
93
-      LineNode node = LineNode();
93
+      final node = LineNode();
94 94
       node.insert(0, 'Hello world', null);
95 95
       node.insert(11, '!!!', null);
96 96
       expect(node, hasLength(15));
@@ -119,7 +119,7 @@ void main() {
119 119
 
120 120
       LineNode line = root.first;
121 121
       expect(line, hasLength(15));
122
-      Delta delta = Delta()
122
+      final delta = Delta()
123 123
         ..insert('Hello ')
124 124
         ..insert('world', boldStyle.toJson())
125 125
         ..insert('!!!\n');
@@ -133,7 +133,7 @@ void main() {
133 133
       LineNode line = root.first;
134 134
       expect(line, hasLength(12));
135 135
 
136
-      Delta delta = Delta()
136
+      final delta = Delta()
137 137
         ..insert('Hello world')
138 138
         ..insert('\n', NotusAttribute.h1.toJson());
139 139
       expect(line.toDelta(), delta);
@@ -187,7 +187,7 @@ void main() {
187 187
       LineNode line = root.first;
188 188
       expect(line, hasLength(8));
189 189
       expect(line.childCount, 1);
190
-      Delta lineDelta = Delta()..insert('Hellord\n');
190
+      final lineDelta = Delta()..insert('Hellord\n');
191 191
       expect(line.toDelta(), lineDelta);
192 192
     });
193 193
 
@@ -198,7 +198,7 @@ void main() {
198 198
       expect(root.childCount, 1);
199 199
       LineNode line = root.first;
200 200
       expect(line, hasLength(18));
201
-      Delta lineDelta = Delta()
201
+      final lineDelta = Delta()
202 202
         ..insert('Hello ')
203 203
         ..insert('worl', boldStyle.toJson())
204 204
         ..insert(' cd ef!\n');
@@ -266,7 +266,7 @@ void main() {
266 266
 
267 267
     test('collectStyle with embed nodes', () {
268 268
       root.insert(0, 'Hello world\n\nMore text.\n', null);
269
-      NotusStyle style = NotusStyle();
269
+      var style = NotusStyle();
270 270
       style = style.put(NotusAttribute.embed.horizontalRule);
271 271
       root.insert(12, EmbedNode.kPlainTextPlaceholder, style);
272 272
 

+ 3
- 3
packages/notus/test/document/node_test.dart View File

@@ -1,8 +1,8 @@
1 1
 // Copyright (c) 2018, the Zefyr project authors.  Please see the AUTHORS file
2 2
 // for details. All rights reserved. Use of this source code is governed by a
3 3
 // BSD-style license that can be found in the LICENSE file.
4
-import 'package:test/test.dart';
5 4
 import 'package:notus/notus.dart';
5
+import 'package:test/test.dart';
6 6
 
7 7
 void main() {
8 8
   group('$Node', () {
@@ -12,8 +12,8 @@ void main() {
12 12
     });
13 13
 
14 14
     test('mounted', () {
15
-      LineNode line = LineNode();
16
-      TextNode text = TextNode();
15
+      final line = LineNode();
16
+      final text = TextNode();
17 17
       expect(text.mounted, isFalse);
18 18
       line.add(text);
19 19
       expect(text.mounted, isTrue);

+ 23
- 22
packages/notus/test/document_test.dart View File

@@ -3,19 +3,20 @@
3 3
 // BSD-style license that can be found in the LICENSE file.
4 4
 import 'dart:convert';
5 5
 
6
-import 'package:test/test.dart';
7
-import 'package:quill_delta/quill_delta.dart';
8 6
 import 'package:notus/notus.dart';
7
+import 'package:quill_delta/quill_delta.dart';
8
+import 'package:test/test.dart';
9
+
9 10
 import 'matchers.dart';
10 11
 
11 12
 NotusDocument dartconfDoc() {
12
-  Delta delta = Delta()..insert('DartConf\nLos Angeles\n');
13
+  final delta = Delta()..insert('DartConf\nLos Angeles\n');
13 14
   return NotusDocument.fromDelta(delta);
14 15
 }
15 16
 
16 17
 NotusDocument dartconfEmbedDoc() {
17 18
   final hr = NotusAttribute.embed.horizontalRule.toJson();
18
-  Delta delta = Delta()
19
+  final delta = Delta()
19 20
     ..insert('DartConf\n')
20 21
     ..insert(kZeroWidthSpace, hr)
21 22
     ..insert('\n')
@@ -39,7 +40,7 @@ void main() {
39 40
     });
40 41
 
41 42
     test('empty document contains single empty line', () {
42
-      NotusDocument doc = NotusDocument();
43
+      final doc = NotusDocument();
43 44
       expect(doc.toPlainText(), '\n');
44 45
     });
45 46
 
@@ -57,17 +58,17 @@ void main() {
57 58
     });
58 59
 
59 60
     test('toString', () {
60
-      NotusDocument doc = dartconfDoc();
61
+      final doc = dartconfDoc();
61 62
       expect(doc.toString(), doc.toString());
62 63
     });
63 64
 
64 65
     test('load non-empty document', () {
65
-      NotusDocument doc = dartconfDoc();
66
+      final doc = dartconfDoc();
66 67
       expect(doc.toPlainText(), 'DartConf\nLos Angeles\n');
67 68
     });
68 69
 
69 70
     test('document delta must end with line-break character', () {
70
-      Delta delta = Delta()..insert('DartConf\nLos Angeles');
71
+      final delta = Delta()..insert('DartConf\nLos Angeles');
71 72
       expect(() {
72 73
         NotusDocument.fromDelta(delta);
73 74
       }, throwsA(const TypeMatcher<AssertionError>()));
@@ -86,14 +87,14 @@ void main() {
86 87
     });
87 88
 
88 89
     test('format applies heuristics', () {
89
-      NotusDocument doc = dartconfDoc();
90
+      final doc = dartconfDoc();
90 91
       doc.format(0, 15, NotusAttribute.ul);
91 92
       expect(doc.root.children, hasLength(1));
92 93
       expect(doc.root.children.first, const TypeMatcher<BlockNode>());
93 94
     });
94 95
 
95 96
     test('format ignores empty changes', () async {
96
-      NotusDocument doc = dartconfDoc();
97
+      final doc = dartconfDoc();
97 98
       var changeList = doc.changes.toList();
98 99
       var change = doc.format(1, 0, NotusAttribute.bold);
99 100
       doc.close();
@@ -103,7 +104,7 @@ void main() {
103 104
     });
104 105
 
105 106
     test('format returns actual change delta', () {
106
-      NotusDocument doc = dartconfDoc();
107
+      final doc = dartconfDoc();
107 108
       final change = doc.format(0, 15, NotusAttribute.ul);
108 109
       final expectedChange = Delta()
109 110
         ..retain(8)
@@ -114,7 +115,7 @@ void main() {
114 115
     });
115 116
 
116 117
     test('format updates document delta', () {
117
-      NotusDocument doc = dartconfDoc();
118
+      final doc = dartconfDoc();
118 119
       doc.format(0, 15, NotusAttribute.ul);
119 120
       final expectedDoc = Delta()
120 121
         ..insert('DartConf')
@@ -125,7 +126,7 @@ void main() {
125 126
     });
126 127
 
127 128
     test('format allows zero-length updates', () {
128
-      NotusDocument doc = dartconfDoc();
129
+      final doc = dartconfDoc();
129 130
       doc.format(0, 0, NotusAttribute.ul);
130 131
       final expectedDoc = Delta()
131 132
         ..insert('DartConf')
@@ -136,7 +137,7 @@ void main() {
136 137
     });
137 138
 
138 139
     test('insert applies heuristics', () {
139
-      NotusDocument doc = dartconfDoc();
140
+      final doc = dartconfDoc();
140 141
       doc.format(0, 15, NotusAttribute.ul);
141 142
       doc.insert(8, '\n');
142 143
       expect(doc.root.children, hasLength(1));
@@ -144,7 +145,7 @@ void main() {
144 145
     });
145 146
 
146 147
     test('insert returns actual change delta', () {
147
-      NotusDocument doc = dartconfDoc();
148
+      final doc = dartconfDoc();
148 149
       doc.format(0, 15, NotusAttribute.ul);
149 150
       final change = doc.insert(8, '\n');
150 151
       final expectedChange = Delta()
@@ -154,7 +155,7 @@ void main() {
154 155
     });
155 156
 
156 157
     test('insert updates document delta', () {
157
-      NotusDocument doc = dartconfDoc();
158
+      final doc = dartconfDoc();
158 159
       doc.format(0, 15, NotusAttribute.ul);
159 160
       doc.insert(8, '\n');
160 161
       final expectedDoc = Delta()
@@ -166,28 +167,28 @@ void main() {
166 167
     });
167 168
 
168 169
     test('insert throws assert error if change is empty', () {
169
-      NotusDocument doc = dartconfDoc();
170
+      final doc = dartconfDoc();
170 171
       expect(() {
171 172
         doc.insert(8, '');
172 173
       }, throwsA(const TypeMatcher<AssertionError>()));
173 174
     });
174 175
 
175 176
     test('replace throws assert error if change is empty', () {
176
-      NotusDocument doc = dartconfDoc();
177
+      final doc = dartconfDoc();
177 178
       expect(() {
178 179
         doc.replace(8, 0, '');
179 180
       }, throwsA(const TypeMatcher<AssertionError>()));
180 181
     });
181 182
 
182 183
     test('compose throws assert error if change is empty', () {
183
-      NotusDocument doc = dartconfDoc();
184
+      final doc = dartconfDoc();
184 185
       expect(() {
185 186
         doc.compose(Delta()..retain(1), ChangeSource.local);
186 187
       }, throwsA(const TypeMatcher<AssertionError>()));
187 188
     });
188 189
 
189 190
     test('replace applies heuristic rules', () {
190
-      NotusDocument doc = dartconfDoc();
191
+      final doc = dartconfDoc();
191 192
       doc.format(0, 0, NotusAttribute.h1);
192 193
       doc.replace(8, 1, ' ');
193 194
       expect(doc.root.children, hasLength(1));
@@ -197,7 +198,7 @@ void main() {
197 198
     });
198 199
 
199 200
     test('delete applies heuristic rules', () {
200
-      NotusDocument doc = dartconfDoc();
201
+      final doc = dartconfDoc();
201 202
       doc.format(0, 0, NotusAttribute.h1);
202 203
       doc.delete(8, 1);
203 204
       expect(doc.root.children, hasLength(1));
@@ -208,7 +209,7 @@ void main() {
208 209
     test('delete which results in an empty change', () {
209 210
       // This test relies on a delete rule which ensures line-breaks around
210 211
       // and embed.
211
-      NotusDocument doc = dartconfEmbedDoc();
212
+      final doc = dartconfEmbedDoc();
212 213
       doc.delete(8, 1);
213 214
       expect(doc.toPlainText(), 'DartConf\n${kZeroWidthSpace}\nLos Angeles\n');
214 215
     });

+ 1
- 1
packages/notus/test/heuristics_test.dart View File

@@ -7,7 +7,7 @@ import 'package:quill_delta/quill_delta.dart';
7 7
 import 'package:test/test.dart';
8 8
 
9 9
 NotusDocument dartconfDoc() {
10
-  Delta delta = Delta()..insert('DartConf\nLos Angeles\n');
10
+  final delta = Delta()..insert('DartConf\nLos Angeles\n');
11 11
   return NotusDocument.fromDelta(delta);
12 12
 }
13 13
 

+ 1
- 0
packages/zefyr/.gitignore View File

@@ -10,6 +10,7 @@ pubspec.lock
10 10
 coverage/
11 11
 ios/Flutter/Generated.xcconfig
12 12
 .flutter-plugins
13
+.flutter-plugins-dependencies
13 14
 example/ios/.symlinks
14 15
 example/ios/Flutter/Generated.xcconfig
15 16
 doc/api/

+ 7
- 0
packages/zefyr/CHANGELOG.md View File

@@ -1,3 +1,10 @@
1
+## 0.9.0
2
+
3
+* Feature: toggle inline styles (works for bold and italic)
4
+* Updated to support Flutter 1.12.0
5
+* Upgraded dependencies
6
+* Fixed analyzer issues
7
+
1 8
 ## 0.8.0
2 9
 
3 10
 * Updated to support Flutter 1.9.0 (#154)

+ 18
- 0
packages/zefyr/example/ios/Flutter/Flutter.podspec View File

@@ -0,0 +1,18 @@
1
+#
2
+# NOTE: This podspec is NOT to be published. It is only used as a local source!
3
+#
4
+
5
+Pod::Spec.new do |s|
6
+  s.name             = 'Flutter'
7
+  s.version          = '1.0.0'
8
+  s.summary          = 'High-performance, high-fidelity mobile apps.'
9
+  s.description      = <<-DESC
10
+Flutter provides an easy and productive way to build and deploy high-performance mobile apps for Android and iOS.
11
+                       DESC
12
+  s.homepage         = 'https://flutter.io'
13
+  s.license          = { :type => 'MIT' }
14
+  s.author           = { 'Flutter Dev Team' => 'flutter-dev@googlegroups.com' }
15
+  s.source           = { :git => 'https://github.com/flutter/engine', :tag => s.version.to_s }
16
+  s.ios.deployment_target = '8.0'
17
+  s.vendored_frameworks = 'Flutter.framework'
18
+end

+ 58
- 34
packages/zefyr/example/ios/Podfile View File

@@ -4,56 +4,80 @@
4 4
 # CocoaPods analytics sends network stats synchronously affecting flutter build latency.
5 5
 ENV['COCOAPODS_DISABLE_STATS'] = 'true'
6 6
 
7
+project 'Runner', {
8
+  'Debug' => :debug,
9
+  'Profile' => :release,
10
+  'Release' => :release,
11
+}
12
+
7 13
 def parse_KV_file(file, separator='=')
8 14
   file_abs_path = File.expand_path(file)
9 15
   if !File.exists? file_abs_path
10 16
     return [];
11 17
   end
12
-  pods_ary = []
18
+  generated_key_values = {}
13 19
   skip_line_start_symbols = ["#", "/"]
14
-  File.foreach(file_abs_path) { |line|
15
-      next if skip_line_start_symbols.any? { |symbol| line =~ /^\s*#{symbol}/ }
16
-      plugin = line.split(pattern=separator)
17
-      if plugin.length == 2
18
-        podname = plugin[0].strip()
19
-        path = plugin[1].strip()
20
-        podpath = File.expand_path("#{path}", file_abs_path)
21
-        pods_ary.push({:name => podname, :path => podpath});
22
-      else
23
-        puts "Invalid plugin specification: #{line}"
24
-      end
25
-  }
26
-  return pods_ary
20
+  File.foreach(file_abs_path) do |line|
21
+    next if skip_line_start_symbols.any? { |symbol| line =~ /^\s*#{symbol}/ }
22
+    plugin = line.split(pattern=separator)
23
+    if plugin.length == 2
24
+      podname = plugin[0].strip()
25
+      path = plugin[1].strip()
26
+      podpath = File.expand_path("#{path}", file_abs_path)
27
+      generated_key_values[podname] = podpath
28
+    else
29
+      puts "Invalid plugin specification: #{line}"
30
+    end
31
+  end
32
+  generated_key_values
27 33
 end
28 34
 
29 35
 target 'Runner' do
30
-  # Prepare symlinks folder. We use symlinks to avoid having Podfile.lock
31
-  # referring to absolute paths on developers' machines.
32
-  system('rm -rf .symlinks')
33
-  system('mkdir -p .symlinks/plugins')
36
+  # Flutter Pod
34 37
 
35
-  # Flutter Pods
36
-  generated_xcode_build_settings = parse_KV_file('./Flutter/Generated.xcconfig')
37
-  if generated_xcode_build_settings.empty?
38
-    puts "Generated.xcconfig must exist. If you're running pod install manually, make sure flutter packages get is executed first."
39
-  end
40
-  generated_xcode_build_settings.map { |p|
41
-    if p[:name] == 'FLUTTER_FRAMEWORK_DIR'
42
-      symlink = File.join('.symlinks', 'flutter')
43
-      File.symlink(File.dirname(p[:path]), symlink)
44
-      pod 'Flutter', :path => File.join(symlink, File.basename(p[:path]))
38
+  copied_flutter_dir = File.join(__dir__, 'Flutter')
39
+  copied_framework_path = File.join(copied_flutter_dir, 'Flutter.framework')
40
+  copied_podspec_path = File.join(copied_flutter_dir, 'Flutter.podspec')
41
+  unless File.exist?(copied_framework_path) && File.exist?(copied_podspec_path)
42
+    # Copy Flutter.framework and Flutter.podspec to Flutter/ to have something to link against if the xcode backend script has not run yet.
43
+    # That script will copy the correct debug/profile/release version of the framework based on the currently selected Xcode configuration.
44
+    # CocoaPods will not embed the framework on pod install (before any build phases can generate) if the dylib does not exist.
45
+
46
+    generated_xcode_build_settings_path = File.join(copied_flutter_dir, 'Generated.xcconfig')
47
+    unless File.exist?(generated_xcode_build_settings_path)
48
+      raise "Generated.xcconfig must exist. If you're running pod install manually, make sure flutter pub get is executed first"
45 49
     end
46
-  }
50
+    generated_xcode_build_settings = parse_KV_file(generated_xcode_build_settings_path)
51
+    cached_framework_dir = generated_xcode_build_settings['FLUTTER_FRAMEWORK_DIR'];
52
+
53
+    unless File.exist?(copied_framework_path)
54
+      FileUtils.cp_r(File.join(cached_framework_dir, 'Flutter.framework'), copied_flutter_dir)
55
+    end
56
+    unless File.exist?(copied_podspec_path)
57
+      FileUtils.cp(File.join(cached_framework_dir, 'Flutter.podspec'), copied_flutter_dir)
58
+    end
59
+  end
60
+
61
+  # Keep pod path relative so it can be checked into Podfile.lock.
62
+  pod 'Flutter', :path => 'Flutter'
47 63
 
48 64
   # Plugin Pods
65
+
66
+  # Prepare symlinks folder. We use symlinks to avoid having Podfile.lock
67
+  # referring to absolute paths on developers' machines.
68
+  system('rm -rf .symlinks')
69
+  system('mkdir -p .symlinks/plugins')
49 70
   plugin_pods = parse_KV_file('../.flutter-plugins')
50
-  plugin_pods.map { |p|
51
-    symlink = File.join('.symlinks', 'plugins', p[:name])
52
-    File.symlink(p[:path], symlink)
53
-    pod p[:name], :path => File.join(symlink, 'ios')
54
-  }
71
+  plugin_pods.each do |name, path|
72
+    symlink = File.join('.symlinks', 'plugins', name)
73
+    File.symlink(path, symlink)
74
+    pod name, :path => File.join(symlink, 'ios')
75
+  end
55 76
 end
56 77
 
78
+# Prevent Cocoapods from embedding a second Flutter framework and causing an error with the new Xcode build system.
79
+install! 'cocoapods', :disable_input_output_paths => true
80
+
57 81
 post_install do |installer|
58 82
   installer.pods_project.targets.each do |target|
59 83
     target.build_configurations.each do |config|

+ 23
- 5
packages/zefyr/example/ios/Podfile.lock View File

@@ -1,28 +1,46 @@
1 1
 PODS:
2 2
   - Flutter (1.0.0)
3
+  - flutter_plugin_android_lifecycle (0.0.1):
4
+    - Flutter
3 5
   - image_picker (0.0.1):
4 6
     - Flutter
5 7
   - url_launcher (0.0.1):
6 8
     - Flutter
9
+  - url_launcher_macos (0.0.1):
10
+    - Flutter
11
+  - url_launcher_web (0.0.1):
12
+    - Flutter
7 13
 
8 14
 DEPENDENCIES:
9
-  - Flutter (from `.symlinks/flutter/ios`)
15
+  - Flutter (from `Flutter`)
16
+  - flutter_plugin_android_lifecycle (from `.symlinks/plugins/flutter_plugin_android_lifecycle/ios`)
10 17
   - image_picker (from `.symlinks/plugins/image_picker/ios`)
11 18
   - url_launcher (from `.symlinks/plugins/url_launcher/ios`)
19
+  - url_launcher_macos (from `.symlinks/plugins/url_launcher_macos/ios`)
20
+  - url_launcher_web (from `.symlinks/plugins/url_launcher_web/ios`)
12 21
 
13 22
 EXTERNAL SOURCES:
14 23
   Flutter:
15
-    :path: ".symlinks/flutter/ios"
24
+    :path: Flutter
25
+  flutter_plugin_android_lifecycle:
26
+    :path: ".symlinks/plugins/flutter_plugin_android_lifecycle/ios"
16 27
   image_picker:
17 28
     :path: ".symlinks/plugins/image_picker/ios"
18 29
   url_launcher:
19 30
     :path: ".symlinks/plugins/url_launcher/ios"
31
+  url_launcher_macos:
32
+    :path: ".symlinks/plugins/url_launcher_macos/ios"
33
+  url_launcher_web:
34
+    :path: ".symlinks/plugins/url_launcher_web/ios"
20 35
 
21 36
 SPEC CHECKSUMS:
22 37
   Flutter: 0e3d915762c693b495b44d77113d4970485de6ec
23
-  image_picker: 16e5fec1fbc87fd3b297c53e4048521eaf17cd06
24
-  url_launcher: 0067ddb8f10d36786672aa0722a21717dba3a298
38
+  flutter_plugin_android_lifecycle: 47de533a02850f070f5696a623995e93eddcdb9b
39
+  image_picker: e3eacd46b94694dde7cf2705955cece853aa1a8f
40
+  url_launcher: a1c0cc845906122c4784c542523d8cacbded5626
41
+  url_launcher_macos: fd7894421cd39320dce5f292fc99ea9270b2a313
42
+  url_launcher_web: e5527357f037c87560776e36436bf2b0288b965c
25 43
 
26
-PODFILE CHECKSUM: 1e5af4103afd21ca5ead147d7b81d06f494f51a2
44
+PODFILE CHECKSUM: 3dbe063e9c90a5d7c9e4e76e70a821b9e2c1d271
27 45
 
28 46
 COCOAPODS: 1.7.2

+ 0
- 3
packages/zefyr/example/ios/Runner.xcodeproj/project.pbxproj View File

@@ -227,12 +227,9 @@
227 227
 			files = (
228 228
 			);
229 229
 			inputPaths = (
230
-				"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh",
231
-				"${PODS_ROOT}/../.symlinks/flutter/ios/Flutter.framework",
232 230
 			);
233 231
 			name = "[CP] Embed Pods Frameworks";
234 232
 			outputPaths = (
235
-				"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Flutter.framework",
236 233
 			);
237 234
 			runOnlyForDeploymentPostprocessing = 0;
238 235
 			shellPath = /bin/sh;

+ 0
- 1
packages/zefyr/lib/src/widgets/buttons.dart View File

@@ -306,7 +306,6 @@ class _LinkButtonState extends State<LinkButton> {
306 306
   final TextEditingController _inputController = TextEditingController();
307 307
   Key _inputKey;
308 308
   bool _formatError = false;
309
-  ZefyrScope _editor;
310 309
 
311 310
   bool get isEditing => _inputKey != null;
312 311
 

+ 3
- 3
packages/zefyr/lib/src/widgets/controller.dart View File

@@ -48,7 +48,7 @@ class ZefyrController extends ChangeNotifier {
48 48
   /// and that has not been applied yet.
49 49
   /// It gets reseted after each format action within the [document].
50 50
   NotusStyle get toggledStyles => _toggledStyles;
51
-  NotusStyle _toggledStyles = new NotusStyle();
51
+  NotusStyle _toggledStyles = NotusStyle();
52 52
 
53 53
   /// Updates selection with specified [value].
54 54
   ///
@@ -127,7 +127,7 @@ class ZefyrController extends ChangeNotifier {
127 127
           delta.length == 2 &&
128 128
           delta[1].isInsert) {
129 129
         // Apply it.
130
-        Delta retainDelta = new Delta()
130
+        Delta retainDelta = Delta()
131 131
           ..retain(index)
132 132
           ..retain(1, toggledStyles.toJson());
133 133
         document.compose(retainDelta, ChangeSource.local);
@@ -135,7 +135,7 @@ class ZefyrController extends ChangeNotifier {
135 135
     }
136 136
 
137 137
     // Always reset it after any user action, even if it has not been applied.
138
-    _toggledStyles = new NotusStyle();
138
+    _toggledStyles = NotusStyle();
139 139
 
140 140
     if (selection != null) {
141 141
       if (delta == null) {

+ 10
- 0
packages/zefyr/lib/src/widgets/input.dart View File

@@ -168,4 +168,14 @@ class InputConnectionController implements TextInputClient {
168 168
   void updateFloatingCursor(RawFloatingCursorPoint point) {
169 169
     // TODO: implement updateFloatingCursor
170 170
   }
171
+
172
+  @override
173
+  void connectionClosed() {
174
+    if (hasConnection) {
175
+      _textInputConnection.connectionClosedReceived();
176
+      _textInputConnection = null;
177
+      _lastKnownRemoteTextEditingValue = null;
178
+      _sentRemoteValues.clear();
179
+    }
180
+  }
171 181
 }

+ 1
- 1
packages/zefyr/lib/src/widgets/scaffold.dart View File

@@ -10,7 +10,7 @@ class ZefyrScaffold extends StatefulWidget {
10 10
 
11 11
   static ZefyrScaffoldState of(BuildContext context) {
12 12
     final _ZefyrScaffoldAccess widget =
13
-        context.inheritFromWidgetOfExactType(_ZefyrScaffoldAccess);
13
+        context.dependOnInheritedWidgetOfExactType<_ZefyrScaffoldAccess>();
14 14
     return widget.scaffold;
15 15
   }
16 16
 

+ 1
- 1
packages/zefyr/lib/src/widgets/scope.dart View File

@@ -59,7 +59,7 @@ class ZefyrScope extends ChangeNotifier {
59 59
 
60 60
   static ZefyrScope of(BuildContext context) {
61 61
     final ZefyrScopeAccess widget =
62
-        context.inheritFromWidgetOfExactType(ZefyrScopeAccess);
62
+        context.dependOnInheritedWidgetOfExactType<ZefyrScopeAccess>();
63 63
     return widget.scope;
64 64
   }
65 65
 

+ 2
- 1
packages/zefyr/lib/src/widgets/theme.dart View File

@@ -42,7 +42,8 @@ class ZefyrTheme extends InheritedWidget {
42 42
   /// and [nullOk] is set to `true`. If [nullOk] is set to `false` (default)
43 43
   /// then this method asserts.
44 44
   static ZefyrThemeData of(BuildContext context, {bool nullOk = false}) {
45
-    final ZefyrTheme widget = context.inheritFromWidgetOfExactType(ZefyrTheme);
45
+    final ZefyrTheme widget =
46
+        context.dependOnInheritedWidgetOfExactType<ZefyrTheme>();
46 47
     if (widget == null && nullOk) return null;
47 48
     assert(widget != null,
48 49
         '$ZefyrTheme.of() called with a context that does not contain a ZefyrEditor.');

+ 1
- 1
packages/zefyr/lib/src/widgets/toolbar.dart View File

@@ -114,7 +114,7 @@ class ZefyrToolbar extends StatefulWidget implements PreferredSizeWidget {
114 114
 
115 115
   static ZefyrToolbarState of(BuildContext context) {
116 116
     final _ZefyrToolbarScope scope =
117
-        context.inheritFromWidgetOfExactType(_ZefyrToolbarScope);
117
+        context.dependOnInheritedWidgetOfExactType<_ZefyrToolbarScope>();
118 118
     return scope?.toolbar;
119 119
   }
120 120
 

+ 2
- 2
packages/zefyr/pubspec.yaml View File

@@ -1,6 +1,6 @@
1 1
 name: zefyr
2 2
 description: Clean, minimalistic and collaboration-ready rich text editor for Flutter.
3
-version: 0.8.0
3
+version: 0.9.0
4 4
 author: Anatoly Pulyaevskiy <anatoly.pulyaevskiy@gmail.com>
5 5
 homepage: https://github.com/memspace/zefyr
6 6
 
@@ -12,7 +12,7 @@ dependencies:
12 12
     sdk: flutter
13 13
   collection: ^1.14.6
14 14
   url_launcher: ^5.0.0
15
-  quill_delta: ^1.0.0-dev.1.0
15
+  quill_delta: ^1.0.0
16 16
   notus: ^0.1.0
17 17
   meta: ^1.1.0
18 18
   quiver_hashcode: ^2.0.0

+ 3
- 3
packages/zefyr/test/widgets/controller_test.dart View File

@@ -106,7 +106,7 @@ void main() {
106 106
 
107 107
       expect(
108 108
         controller.document.toDelta(),
109
-        new Delta()
109
+        Delta()
110 110
           ..insert('Won')
111 111
           ..insert('B', NotusAttribute.bold.toJson())
112 112
           ..insert('rds')
@@ -129,7 +129,7 @@ void main() {
129 129
       expect(notified, isTrue);
130 130
       expect(
131 131
         controller.document.toDelta(),
132
-        new Delta()
132
+        Delta()
133 133
           ..insert('W')
134 134
           ..insert('B', NotusAttribute.bold.toJson())
135 135
           ..insert('uords')
@@ -163,7 +163,7 @@ void main() {
163 163
     });
164 164
 
165 165
     test('getSelectionStyle with toggled style', () {
166
-      var selection = new TextSelection.collapsed(offset: 3);
166
+      var selection = TextSelection.collapsed(offset: 3);
167 167
       controller.replaceText(0, 0, 'Words', selection: selection);
168 168
       controller.formatText(3, 0, NotusAttribute.bold);
169 169