Browse Source

Upgraded to Flutter 1.12; fixed analyzer issues

Anatoly Pulyaevskiy 5 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
 .DS_Store
1
 .DS_Store
2
 .idea/
2
 .idea/
3
+.dart_tool/

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

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

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

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

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

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

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

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

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

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

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

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

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

42
   /// To get offset of this node in the document see [documentOffset].
42
   /// To get offset of this node in the document see [documentOffset].
43
   int get offset {
43
   int get offset {
44
     if (isFirst) return 0;
44
     if (isFirst) return 0;
45
-    int offset = 0;
46
-    Node node = this;
45
+    var offset = 0;
46
+    var node = this;
47
     do {
47
     do {
48
       node = node.previous;
48
       node = node.previous;
49
       offset += node.length;
49
       offset += node.length;
53
 
53
 
54
   /// Offset in characters of this node in the document.
54
   /// Offset in characters of this node in the document.
55
   int get documentOffset {
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
   /// Returns `true` if this node contains character at specified [offset] in
60
   /// Returns `true` if this node contains character at specified [offset] in
61
   /// the document.
61
   /// the document.
62
   bool containsOffset(int offset) {
62
   bool containsOffset(int offset) {
63
-    int o = documentOffset;
63
+    final o = documentOffset;
64
     return o <= offset && offset < o + length;
64
     return o <= offset && offset < o + length;
65
   }
65
   }
66
 
66
 
208
   /// which points at the same character position in the document as the
208
   /// which points at the same character position in the document as the
209
   /// original [offset].
209
   /// original [offset].
210
   LookupResult lookup(int offset, {bool inclusive = false}) {
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
       if (offset < length || (inclusive && offset == length && (node.isLast))) {
215
       if (offset < length || (inclusive && offset == length && (node.isLast))) {
216
         return LookupResult(node, offset);
216
         return LookupResult(node, offset);
217
       }
217
       }
238
 
238
 
239
     if (isEmpty) {
239
     if (isEmpty) {
240
       assert(index == 0);
240
       assert(index == 0);
241
-      T node = defaultChild;
241
+      final node = defaultChild;
242
       add(node);
242
       add(node);
243
       node.insert(index, value, style);
243
       node.insert(index, value, style);
244
     } else {
244
     } else {
245
-      LookupResult result = lookup(index);
245
+      final result = lookup(index);
246
       result.node.insert(result.offset, value, style);
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
 // for details. All rights reserved. Use of this source code is governed by a
2
 // for details. All rights reserved. Use of this source code is governed by a
3
 // BSD-style license that can be found in the LICENSE file.
3
 // BSD-style license that can be found in the LICENSE file.
4
 
4
 
5
-import 'package:quill_delta/quill_delta.dart';
6
 import 'package:notus/notus.dart';
5
 import 'package:notus/notus.dart';
6
+import 'package:quill_delta/quill_delta.dart';
7
 
7
 
8
 /// A heuristic rule for delete operations.
8
 /// A heuristic rule for delete operations.
9
 abstract class DeleteRule {
9
 abstract class DeleteRule {
39
 
39
 
40
   @override
40
   @override
41
   Delta apply(Delta document, int index, int length) {
41
   Delta apply(Delta document, int index, int length) {
42
-    DeltaIterator iter = DeltaIterator(document);
42
+    final iter = DeltaIterator(document);
43
     iter.skip(index);
43
     iter.skip(index);
44
     final target = iter.next(1);
44
     final target = iter.next(1);
45
     if (target.data != '\n') return null;
45
     if (target.data != '\n') return null;
46
     iter.skip(length - 1);
46
     iter.skip(length - 1);
47
-    final Delta result = Delta()
47
+    final result = Delta()
48
       ..retain(index)
48
       ..retain(index)
49
       ..delete(length);
49
       ..delete(length);
50
 
50
 
51
     // Look for next line-break to apply the attributes
51
     // Look for next line-break to apply the attributes
52
     while (iter.hasNext) {
52
     while (iter.hasNext) {
53
       final op = iter.next();
53
       final op = iter.next();
54
-      int lf = op.data.indexOf('\n');
54
+      final lf = op.data.indexOf('\n');
55
       if (lf == -1) {
55
       if (lf == -1) {
56
         result..retain(op.length);
56
         result..retain(op.length);
57
         continue;
57
         continue;
80
 
80
 
81
   @override
81
   @override
82
   Delta apply(Delta document, int index, int length) {
82
   Delta apply(Delta document, int index, int length) {
83
-    DeltaIterator iter = DeltaIterator(document);
83
+    final iter = DeltaIterator(document);
84
 
84
 
85
     // First, check if line-break deleted after an embed.
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
     if (op != null && op.data.endsWith(kZeroWidthSpace)) {
92
     if (op != null && op.data.endsWith(kZeroWidthSpace)) {
93
       foundEmbed = true;
93
       foundEmbed = true;
94
-      Operation candidate = iter.next(1);
94
+      var candidate = iter.next(1);
95
       remaining--;
95
       remaining--;
96
       if (candidate.data == '\n') {
96
       if (candidate.data == '\n') {
97
         indexDelta += 1;
97
         indexDelta += 1;

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

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

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

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

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

5
 homepage: https://github.com/memspace/zefyr
5
 homepage: https://github.com/memspace/zefyr
6
 
6
 
7
 environment:
7
 environment:
8
-  sdk: '>=2.0.0 <3.0.0'
8
+  sdk: '>=2.2.0 <3.0.0'
9
 
9
 
10
 dependencies:
10
 dependencies:
11
   collection: ^1.14.6
11
   collection: ^1.14.6
15
 
15
 
16
 dev_dependencies:
16
 dev_dependencies:
17
   pedantic: ^1.0.0
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
 // BSD-style license that can be found in the LICENSE file.
3
 // BSD-style license that can be found in the LICENSE file.
4
 import 'dart:convert';
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
 import 'package:notus/convert.dart';
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
 void main() {
11
 void main() {
12
   group('$NotusMarkdownCodec.encode', () {
12
   group('$NotusMarkdownCodec.encode', () {
25
     });
25
     });
26
 
26
 
27
     test('bold italic', () {
27
     test('bold italic', () {
28
-      runFor(NotusAttribute<bool> attribute, String expected) {
28
+      void runFor(NotusAttribute<bool> attribute, String expected) {
29
         final delta = Delta()
29
         final delta = Delta()
30
           ..insert('This ')
30
           ..insert('This ')
31
           ..insert('house', attribute.toJson())
31
           ..insert('house', attribute.toJson())
87
     });
87
     });
88
 
88
 
89
     test('heading styles', () {
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
         final delta = Delta()..insert(source)..insert('\n', attribute.toJson());
92
         final delta = Delta()..insert(source)..insert('\n', attribute.toJson());
92
         final result = notusMarkdown.encode(delta);
93
         final result = notusMarkdown.encode(delta);
93
         expect(result, expected);
94
         expect(result, expected);
99
     });
100
     });
100
 
101
 
101
     test('block styles', () {
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
         final delta = Delta()..insert(source)..insert('\n', attribute.toJson());
105
         final delta = Delta()..insert(source)..insert('\n', attribute.toJson());
104
         final result = notusMarkdown.encode(delta);
106
         final result = notusMarkdown.encode(delta);
105
         expect(result, expected);
107
         expect(result, expected);
112
     });
114
     });
113
 
115
 
114
     test('multiline blocks', () {
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
         final delta = Delta()
119
         final delta = Delta()
117
           ..insert(source)
120
           ..insert(source)
118
           ..insert('\n', attribute.toJson())
121
           ..insert('\n', attribute.toJson())

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

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

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

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

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

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

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

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

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

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

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

10
 coverage/
10
 coverage/
11
 ios/Flutter/Generated.xcconfig
11
 ios/Flutter/Generated.xcconfig
12
 .flutter-plugins
12
 .flutter-plugins
13
+.flutter-plugins-dependencies
13
 example/ios/.symlinks
14
 example/ios/.symlinks
14
 example/ios/Flutter/Generated.xcconfig
15
 example/ios/Flutter/Generated.xcconfig
15
 doc/api/
16
 doc/api/

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

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
 ## 0.8.0
8
 ## 0.8.0
2
 
9
 
3
 * Updated to support Flutter 1.9.0 (#154)
10
 * Updated to support Flutter 1.9.0 (#154)

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

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
 # CocoaPods analytics sends network stats synchronously affecting flutter build latency.
4
 # CocoaPods analytics sends network stats synchronously affecting flutter build latency.
5
 ENV['COCOAPODS_DISABLE_STATS'] = 'true'
5
 ENV['COCOAPODS_DISABLE_STATS'] = 'true'
6
 
6
 
7
+project 'Runner', {
8
+  'Debug' => :debug,
9
+  'Profile' => :release,
10
+  'Release' => :release,
11
+}
12
+
7
 def parse_KV_file(file, separator='=')
13
 def parse_KV_file(file, separator='=')
8
   file_abs_path = File.expand_path(file)
14
   file_abs_path = File.expand_path(file)
9
   if !File.exists? file_abs_path
15
   if !File.exists? file_abs_path
10
     return [];
16
     return [];
11
   end
17
   end
12
-  pods_ary = []
18
+  generated_key_values = {}
13
   skip_line_start_symbols = ["#", "/"]
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
 end
33
 end
28
 
34
 
29
 target 'Runner' do
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
     end
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
   # Plugin Pods
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
   plugin_pods = parse_KV_file('../.flutter-plugins')
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
 end
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
 post_install do |installer|
81
 post_install do |installer|
58
   installer.pods_project.targets.each do |target|
82
   installer.pods_project.targets.each do |target|
59
     target.build_configurations.each do |config|
83
     target.build_configurations.each do |config|

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

1
 PODS:
1
 PODS:
2
   - Flutter (1.0.0)
2
   - Flutter (1.0.0)
3
+  - flutter_plugin_android_lifecycle (0.0.1):
4
+    - Flutter
3
   - image_picker (0.0.1):
5
   - image_picker (0.0.1):
4
     - Flutter
6
     - Flutter
5
   - url_launcher (0.0.1):
7
   - url_launcher (0.0.1):
6
     - Flutter
8
     - Flutter
9
+  - url_launcher_macos (0.0.1):
10
+    - Flutter
11
+  - url_launcher_web (0.0.1):
12
+    - Flutter
7
 
13
 
8
 DEPENDENCIES:
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
   - image_picker (from `.symlinks/plugins/image_picker/ios`)
17
   - image_picker (from `.symlinks/plugins/image_picker/ios`)
11
   - url_launcher (from `.symlinks/plugins/url_launcher/ios`)
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
 EXTERNAL SOURCES:
22
 EXTERNAL SOURCES:
14
   Flutter:
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
   image_picker:
27
   image_picker:
17
     :path: ".symlinks/plugins/image_picker/ios"
28
     :path: ".symlinks/plugins/image_picker/ios"
18
   url_launcher:
29
   url_launcher:
19
     :path: ".symlinks/plugins/url_launcher/ios"
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
 SPEC CHECKSUMS:
36
 SPEC CHECKSUMS:
22
   Flutter: 0e3d915762c693b495b44d77113d4970485de6ec
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
 COCOAPODS: 1.7.2
46
 COCOAPODS: 1.7.2

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

227
 			files = (
227
 			files = (
228
 			);
228
 			);
229
 			inputPaths = (
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
 			name = "[CP] Embed Pods Frameworks";
231
 			name = "[CP] Embed Pods Frameworks";
234
 			outputPaths = (
232
 			outputPaths = (
235
-				"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Flutter.framework",
236
 			);
233
 			);
237
 			runOnlyForDeploymentPostprocessing = 0;
234
 			runOnlyForDeploymentPostprocessing = 0;
238
 			shellPath = /bin/sh;
235
 			shellPath = /bin/sh;

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

306
   final TextEditingController _inputController = TextEditingController();
306
   final TextEditingController _inputController = TextEditingController();
307
   Key _inputKey;
307
   Key _inputKey;
308
   bool _formatError = false;
308
   bool _formatError = false;
309
-  ZefyrScope _editor;
310
 
309
 
311
   bool get isEditing => _inputKey != null;
310
   bool get isEditing => _inputKey != null;
312
 
311
 

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

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

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

168
   void updateFloatingCursor(RawFloatingCursorPoint point) {
168
   void updateFloatingCursor(RawFloatingCursorPoint point) {
169
     // TODO: implement updateFloatingCursor
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
 
10
 
11
   static ZefyrScaffoldState of(BuildContext context) {
11
   static ZefyrScaffoldState of(BuildContext context) {
12
     final _ZefyrScaffoldAccess widget =
12
     final _ZefyrScaffoldAccess widget =
13
-        context.inheritFromWidgetOfExactType(_ZefyrScaffoldAccess);
13
+        context.dependOnInheritedWidgetOfExactType<_ZefyrScaffoldAccess>();
14
     return widget.scaffold;
14
     return widget.scaffold;
15
   }
15
   }
16
 
16
 

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

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

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

42
   /// and [nullOk] is set to `true`. If [nullOk] is set to `false` (default)
42
   /// and [nullOk] is set to `true`. If [nullOk] is set to `false` (default)
43
   /// then this method asserts.
43
   /// then this method asserts.
44
   static ZefyrThemeData of(BuildContext context, {bool nullOk = false}) {
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
     if (widget == null && nullOk) return null;
47
     if (widget == null && nullOk) return null;
47
     assert(widget != null,
48
     assert(widget != null,
48
         '$ZefyrTheme.of() called with a context that does not contain a ZefyrEditor.');
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
 
114
 
115
   static ZefyrToolbarState of(BuildContext context) {
115
   static ZefyrToolbarState of(BuildContext context) {
116
     final _ZefyrToolbarScope scope =
116
     final _ZefyrToolbarScope scope =
117
-        context.inheritFromWidgetOfExactType(_ZefyrToolbarScope);
117
+        context.dependOnInheritedWidgetOfExactType<_ZefyrToolbarScope>();
118
     return scope?.toolbar;
118
     return scope?.toolbar;
119
   }
119
   }
120
 
120
 

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

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

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

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