Skip to content

Commit eb90d6e

Browse files
authored
Add toPlainText method to EmbedBuilder and Revert example (singerdmx#1280)
1 parent 7544ac1 commit eb90d6e

File tree

8 files changed

+147
-95
lines changed

8 files changed

+147
-95
lines changed

example/lib/pages/home_page.dart

Lines changed: 47 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import 'package:path/path.dart';
1414
import 'package:path_provider/path_provider.dart';
1515

1616
import '../universal_ui/universal_ui.dart';
17+
import '../widgets/time_stamp_embed_widget.dart';
1718
import 'read_only_page.dart';
1819

1920
enum _SelectionType {
@@ -80,9 +81,24 @@ class _HomePageState extends State<HomePage> {
8081
),
8182
actions: [
8283
IconButton(
83-
onPressed: () => _addEditNote(context),
84-
icon: const Icon(Icons.note_add),
84+
onPressed: () => _insertTimeStamp(
85+
_controller!,
86+
DateTime.now().toString(),
87+
),
88+
icon: const Icon(Icons.add_alarm_rounded),
8589
),
90+
IconButton(
91+
onPressed: () => showDialog(
92+
context: context,
93+
builder: (context) => AlertDialog(
94+
content: Text(_controller!.document.toPlainText([
95+
...FlutterQuillEmbeds.builders(),
96+
TimeStampEmbedBuilderWidget()
97+
])),
98+
),
99+
),
100+
icon: const Icon(Icons.text_fields_rounded),
101+
)
86102
],
87103
),
88104
drawer: Container(
@@ -188,7 +204,7 @@ class _HomePageState extends State<HomePage> {
188204
),
189205
embedBuilders: [
190206
...FlutterQuillEmbeds.builders(),
191-
NotesEmbedBuilder(addEditNote: _addEditNote)
207+
TimeStampEmbedBuilderWidget()
192208
],
193209
);
194210
if (kIsWeb) {
@@ -220,7 +236,7 @@ class _HomePageState extends State<HomePage> {
220236
),
221237
embedBuilders: [
222238
...defaultEmbedBuildersWeb,
223-
NotesEmbedBuilder(addEditNote: _addEditNote),
239+
TimeStampEmbedBuilderWidget()
224240
]);
225241
}
226242
var toolbar = QuillToolbar.basic(
@@ -433,99 +449,41 @@ class _HomePageState extends State<HomePage> {
433449
return file.path.toString();
434450
}
435451

436-
Future<void> _addEditNote(BuildContext context, {Document? document}) async {
437-
final isEditing = document != null;
438-
final quillEditorController = QuillController(
439-
document: document ?? Document(),
440-
selection: const TextSelection.collapsed(offset: 0),
441-
);
442-
443-
await showDialog(
444-
context: context,
445-
builder: (context) => AlertDialog(
446-
titlePadding: const EdgeInsets.only(left: 16, top: 8),
447-
title: Row(
448-
mainAxisAlignment: MainAxisAlignment.spaceBetween,
449-
children: [
450-
Text('${isEditing ? 'Edit' : 'Add'} note'),
451-
IconButton(
452-
onPressed: () => Navigator.of(context).pop(),
453-
icon: const Icon(Icons.close),
454-
)
455-
],
456-
),
457-
content: QuillEditor.basic(
458-
controller: quillEditorController,
459-
readOnly: false,
460-
),
452+
static void _insertTimeStamp(QuillController controller, String string) {
453+
controller.document.insert(controller.selection.extentOffset, '\n');
454+
controller.updateSelection(
455+
TextSelection.collapsed(
456+
offset: controller.selection.extentOffset + 1,
461457
),
458+
ChangeSource.LOCAL,
462459
);
463460

464-
if (quillEditorController.document.isEmpty()) return;
465-
466-
final block = BlockEmbed.custom(
467-
NotesBlockEmbed.fromDocument(quillEditorController.document),
461+
controller.document.insert(
462+
controller.selection.extentOffset,
463+
TimeStampEmbed(string),
468464
);
469-
final controller = _controller!;
470-
final index = controller.selection.baseOffset;
471-
final length = controller.selection.extentOffset - index;
472-
473-
if (isEditing) {
474-
final offset =
475-
getEmbedNode(controller, controller.selection.start).offset;
476-
controller.replaceText(
477-
offset, 1, block, TextSelection.collapsed(offset: offset));
478-
} else {
479-
controller.replaceText(index, length, block, null);
480-
}
481-
}
482-
}
483465

484-
class NotesEmbedBuilder extends EmbedBuilder {
485-
NotesEmbedBuilder({required this.addEditNote});
486-
487-
Future<void> Function(BuildContext context, {Document? document}) addEditNote;
466+
controller.updateSelection(
467+
TextSelection.collapsed(
468+
offset: controller.selection.extentOffset + 1,
469+
),
470+
ChangeSource.LOCAL,
471+
);
488472

489-
@override
490-
String get key => 'notes';
473+
controller.document.insert(controller.selection.extentOffset, ' ');
474+
controller.updateSelection(
475+
TextSelection.collapsed(
476+
offset: controller.selection.extentOffset + 1,
477+
),
478+
ChangeSource.LOCAL,
479+
);
491480

492-
@override
493-
Widget build(
494-
BuildContext context,
495-
QuillController controller,
496-
Embed node,
497-
bool readOnly,
498-
bool inline,
499-
TextStyle textStyle,
500-
) {
501-
final notes = NotesBlockEmbed(node.value.data).document;
502-
503-
return Material(
504-
color: Colors.transparent,
505-
child: ListTile(
506-
title: Text(
507-
notes.toPlainText().replaceAll('\n', ' '),
508-
maxLines: 3,
509-
overflow: TextOverflow.ellipsis,
510-
),
511-
leading: const Icon(Icons.notes),
512-
onTap: () => addEditNote(context, document: notes),
513-
shape: RoundedRectangleBorder(
514-
borderRadius: BorderRadius.circular(10),
515-
side: const BorderSide(color: Colors.grey),
516-
),
481+
controller.document.insert(controller.selection.extentOffset, '\n');
482+
controller.updateSelection(
483+
TextSelection.collapsed(
484+
offset: controller.selection.extentOffset + 1,
517485
),
486+
ChangeSource.LOCAL,
518487
);
519488
}
520489
}
521-
522-
class NotesBlockEmbed extends CustomBlockEmbed {
523-
const NotesBlockEmbed(String value) : super(noteType, value);
524-
525-
static const String noteType = 'notes';
526-
527-
static NotesBlockEmbed fromDocument(Document document) =>
528-
NotesBlockEmbed(jsonEncode(document.toDelta().toJson()));
529-
530-
Document get document => Document.fromJson(jsonDecode(data));
531-
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import 'dart:convert';
2+
3+
import 'package:flutter/material.dart';
4+
import 'package:flutter_quill/flutter_quill.dart' hide Text;
5+
6+
class TimeStampEmbed extends Embeddable {
7+
const TimeStampEmbed(
8+
String value,
9+
) : super(timeStampType, value);
10+
11+
static const String timeStampType = 'timeStamp';
12+
13+
static TimeStampEmbed fromDocument(Document document) =>
14+
TimeStampEmbed(jsonEncode(document.toDelta().toJson()));
15+
16+
Document get document => Document.fromJson(jsonDecode(data));
17+
}
18+
19+
class TimeStampEmbedBuilderWidget extends EmbedBuilder {
20+
@override
21+
String get key => 'timeStamp';
22+
23+
@override
24+
String toPlainText(Embed embed) {
25+
return embed.value.data;
26+
}
27+
28+
@override
29+
Widget build(
30+
BuildContext context,
31+
QuillController controller,
32+
Embed node,
33+
bool readOnly,
34+
bool inline,
35+
TextStyle textStyle,
36+
) {
37+
return Row(
38+
children: [
39+
const Icon(Icons.access_time_rounded),
40+
Text(node.value.data as String),
41+
],
42+
);
43+
}
44+
}

lib/src/models/documents/document.dart

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import 'dart:async';
22

3+
import '../../widgets/embeds.dart';
34
import '../quill_delta.dart';
45
import '../rules/rule.dart';
56
import '../structs/doc_change.dart';
@@ -349,7 +350,13 @@ class Document {
349350
}
350351

351352
/// Returns plain text representation of this document.
352-
String toPlainText() => _root.children.map((e) => e.toPlainText()).join();
353+
String toPlainText([
354+
Iterable<EmbedBuilder>? embedBuilders,
355+
EmbedBuilder? unknownEmbedBuilder,
356+
]) =>
357+
_root.children
358+
.map((e) => e.toPlainText(embedBuilders, unknownEmbedBuilder))
359+
.join();
353360

354361
void _loadDocument(Delta doc) {
355362
if (doc.isEmpty) {

lib/src/models/documents/nodes/container.dart

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import 'dart:collection';
22

3+
import '../../../widgets/embeds.dart';
34
import '../style.dart';
45
import 'leaf.dart';
56
import 'line.dart';
@@ -103,7 +104,13 @@ abstract class Container<T extends Node?> extends Node {
103104
}
104105

105106
@override
106-
String toPlainText() => children.map((child) => child.toPlainText()).join();
107+
String toPlainText([
108+
Iterable<EmbedBuilder>? embedBuilders,
109+
EmbedBuilder? unknownEmbedBuilder,
110+
]) =>
111+
children
112+
.map((e) => e.toPlainText(embedBuilders, unknownEmbedBuilder))
113+
.join();
107114

108115
/// Content length of this node's children.
109116
///

lib/src/models/documents/nodes/leaf.dart

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import 'dart:math' as math;
22

3+
import '../../../widgets/embeds.dart';
34
import '../../quill_delta.dart';
45
import '../style.dart';
56
import 'embeddable.dart';
@@ -224,7 +225,11 @@ class Text extends Leaf {
224225
String get value => _value as String;
225226

226227
@override
227-
String toPlainText() => value;
228+
String toPlainText([
229+
Iterable<EmbedBuilder>? embedBuilders,
230+
EmbedBuilder? unknownEmbedBuilder,
231+
]) =>
232+
value;
228233
}
229234

230235
/// An embed node inside of a line in a Quill document.
@@ -257,7 +262,26 @@ class Embed extends Leaf {
257262
// Embed nodes are represented as unicode object replacement character in
258263
// plain text.
259264
@override
260-
String toPlainText() => kObjectReplacementCharacter;
265+
String toPlainText([
266+
Iterable<EmbedBuilder>? embedBuilders,
267+
EmbedBuilder? unknownEmbedBuilder,
268+
]) {
269+
final builders = embedBuilders;
270+
271+
if (builders != null) {
272+
for (final builder in builders) {
273+
if (builder.key == value.type) {
274+
return builder.toPlainText(this);
275+
}
276+
}
277+
}
278+
279+
if (unknownEmbedBuilder != null) {
280+
return unknownEmbedBuilder.toPlainText(this);
281+
}
282+
283+
return Embed.kObjectReplacementCharacter;
284+
}
261285

262286
@override
263287
String toString() => '${super.toString()} ${value.type}';

lib/src/models/documents/nodes/line.dart

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import 'dart:math' as math;
22

33
import 'package:collection/collection.dart';
44

5+
import '../../../widgets/embeds.dart';
56
import '../../quill_delta.dart';
67
import '../../structs/offset_value.dart';
78
import '../attribute.dart';
@@ -65,7 +66,11 @@ class Line extends Container<Leaf?> {
6566
}
6667

6768
@override
68-
String toPlainText() => '${super.toPlainText()}\n';
69+
String toPlainText([
70+
Iterable<EmbedBuilder>? embedBuilders,
71+
EmbedBuilder? unknownEmbedBuilder,
72+
]) =>
73+
'${super.toPlainText(embedBuilders, unknownEmbedBuilder)}\n';
6974

7075
@override
7176
String toString() {

lib/src/models/documents/nodes/node.dart

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import 'dart:collection';
22

3+
import '../../../widgets/embeds.dart';
34
import '../../quill_delta.dart';
45
import '../attribute.dart';
56
import '../style.dart';
@@ -109,7 +110,10 @@ abstract class Node extends LinkedListEntry<Node> {
109110
110111
Node newInstance();
111112

112-
String toPlainText();
113+
String toPlainText([
114+
Iterable<EmbedBuilder>? embedBuilders,
115+
EmbedBuilder? unknownEmbedBuilder,
116+
]);
113117

114118
Delta toDelta();
115119

lib/src/widgets/embeds.dart

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import 'package:flutter/material.dart';
22

3+
import '../../extensions.dart';
34
import '../models/documents/nodes/leaf.dart' as leaf;
45
import '../models/themes/quill_dialog_theme.dart';
56
import '../models/themes/quill_icon_theme.dart';
@@ -15,6 +16,8 @@ abstract class EmbedBuilder {
1516
return WidgetSpan(child: widget);
1617
}
1718

19+
String toPlainText(Embed node) => Embed.kObjectReplacementCharacter;
20+
1821
Widget build(
1922
BuildContext context,
2023
QuillController controller,

0 commit comments

Comments
 (0)