Add toPlainText method to `EmbedBuilder` and Revert example (#1280)

pull/1282/head
Cierra_Runis 2 years ago committed by GitHub
parent 7544ac12f1
commit eb90d6ea65
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 136
      example/lib/pages/home_page.dart
  2. 44
      example/lib/widgets/time_stamp_embed_widget.dart
  3. 9
      lib/src/models/documents/document.dart
  4. 9
      lib/src/models/documents/nodes/container.dart
  5. 28
      lib/src/models/documents/nodes/leaf.dart
  6. 7
      lib/src/models/documents/nodes/line.dart
  7. 6
      lib/src/models/documents/nodes/node.dart
  8. 3
      lib/src/widgets/embeds.dart

@ -14,6 +14,7 @@ import 'package:path/path.dart';
import 'package:path_provider/path_provider.dart'; import 'package:path_provider/path_provider.dart';
import '../universal_ui/universal_ui.dart'; import '../universal_ui/universal_ui.dart';
import '../widgets/time_stamp_embed_widget.dart';
import 'read_only_page.dart'; import 'read_only_page.dart';
enum _SelectionType { enum _SelectionType {
@ -80,9 +81,24 @@ class _HomePageState extends State<HomePage> {
), ),
actions: [ actions: [
IconButton( IconButton(
onPressed: () => _addEditNote(context), onPressed: () => _insertTimeStamp(
icon: const Icon(Icons.note_add), _controller!,
DateTime.now().toString(),
), ),
icon: const Icon(Icons.add_alarm_rounded),
),
IconButton(
onPressed: () => showDialog(
context: context,
builder: (context) => AlertDialog(
content: Text(_controller!.document.toPlainText([
...FlutterQuillEmbeds.builders(),
TimeStampEmbedBuilderWidget()
])),
),
),
icon: const Icon(Icons.text_fields_rounded),
)
], ],
), ),
drawer: Container( drawer: Container(
@ -188,7 +204,7 @@ class _HomePageState extends State<HomePage> {
), ),
embedBuilders: [ embedBuilders: [
...FlutterQuillEmbeds.builders(), ...FlutterQuillEmbeds.builders(),
NotesEmbedBuilder(addEditNote: _addEditNote) TimeStampEmbedBuilderWidget()
], ],
); );
if (kIsWeb) { if (kIsWeb) {
@ -220,7 +236,7 @@ class _HomePageState extends State<HomePage> {
), ),
embedBuilders: [ embedBuilders: [
...defaultEmbedBuildersWeb, ...defaultEmbedBuildersWeb,
NotesEmbedBuilder(addEditNote: _addEditNote), TimeStampEmbedBuilderWidget()
]); ]);
} }
var toolbar = QuillToolbar.basic( var toolbar = QuillToolbar.basic(
@ -433,99 +449,41 @@ class _HomePageState extends State<HomePage> {
return file.path.toString(); return file.path.toString();
} }
Future<void> _addEditNote(BuildContext context, {Document? document}) async { static void _insertTimeStamp(QuillController controller, String string) {
final isEditing = document != null; controller.document.insert(controller.selection.extentOffset, '\n');
final quillEditorController = QuillController( controller.updateSelection(
document: document ?? Document(), TextSelection.collapsed(
selection: const TextSelection.collapsed(offset: 0), offset: controller.selection.extentOffset + 1,
);
await showDialog(
context: context,
builder: (context) => AlertDialog(
titlePadding: const EdgeInsets.only(left: 16, top: 8),
title: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text('${isEditing ? 'Edit' : 'Add'} note'),
IconButton(
onPressed: () => Navigator.of(context).pop(),
icon: const Icon(Icons.close),
)
],
),
content: QuillEditor.basic(
controller: quillEditorController,
readOnly: false,
),
), ),
ChangeSource.LOCAL,
); );
if (quillEditorController.document.isEmpty()) return; controller.document.insert(
controller.selection.extentOffset,
final block = BlockEmbed.custom( TimeStampEmbed(string),
NotesBlockEmbed.fromDocument(quillEditorController.document),
); );
final controller = _controller!;
final index = controller.selection.baseOffset;
final length = controller.selection.extentOffset - index;
if (isEditing) {
final offset =
getEmbedNode(controller, controller.selection.start).offset;
controller.replaceText(
offset, 1, block, TextSelection.collapsed(offset: offset));
} else {
controller.replaceText(index, length, block, null);
}
}
}
class NotesEmbedBuilder extends EmbedBuilder { controller.updateSelection(
NotesEmbedBuilder({required this.addEditNote}); TextSelection.collapsed(
offset: controller.selection.extentOffset + 1,
Future<void> Function(BuildContext context, {Document? document}) addEditNote;
@override
String get key => 'notes';
@override
Widget build(
BuildContext context,
QuillController controller,
Embed node,
bool readOnly,
bool inline,
TextStyle textStyle,
) {
final notes = NotesBlockEmbed(node.value.data).document;
return Material(
color: Colors.transparent,
child: ListTile(
title: Text(
notes.toPlainText().replaceAll('\n', ' '),
maxLines: 3,
overflow: TextOverflow.ellipsis,
), ),
leading: const Icon(Icons.notes), ChangeSource.LOCAL,
onTap: () => addEditNote(context, document: notes), );
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10), controller.document.insert(controller.selection.extentOffset, ' ');
side: const BorderSide(color: Colors.grey), controller.updateSelection(
TextSelection.collapsed(
offset: controller.selection.extentOffset + 1,
), ),
ChangeSource.LOCAL,
);
controller.document.insert(controller.selection.extentOffset, '\n');
controller.updateSelection(
TextSelection.collapsed(
offset: controller.selection.extentOffset + 1,
), ),
ChangeSource.LOCAL,
); );
} }
} }
class NotesBlockEmbed extends CustomBlockEmbed {
const NotesBlockEmbed(String value) : super(noteType, value);
static const String noteType = 'notes';
static NotesBlockEmbed fromDocument(Document document) =>
NotesBlockEmbed(jsonEncode(document.toDelta().toJson()));
Document get document => Document.fromJson(jsonDecode(data));
}

@ -0,0 +1,44 @@
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter_quill/flutter_quill.dart' hide Text;
class TimeStampEmbed extends Embeddable {
const TimeStampEmbed(
String value,
) : super(timeStampType, value);
static const String timeStampType = 'timeStamp';
static TimeStampEmbed fromDocument(Document document) =>
TimeStampEmbed(jsonEncode(document.toDelta().toJson()));
Document get document => Document.fromJson(jsonDecode(data));
}
class TimeStampEmbedBuilderWidget extends EmbedBuilder {
@override
String get key => 'timeStamp';
@override
String toPlainText(Embed embed) {
return embed.value.data;
}
@override
Widget build(
BuildContext context,
QuillController controller,
Embed node,
bool readOnly,
bool inline,
TextStyle textStyle,
) {
return Row(
children: [
const Icon(Icons.access_time_rounded),
Text(node.value.data as String),
],
);
}
}

@ -1,5 +1,6 @@
import 'dart:async'; import 'dart:async';
import '../../widgets/embeds.dart';
import '../quill_delta.dart'; import '../quill_delta.dart';
import '../rules/rule.dart'; import '../rules/rule.dart';
import '../structs/doc_change.dart'; import '../structs/doc_change.dart';
@ -349,7 +350,13 @@ class Document {
} }
/// Returns plain text representation of this document. /// Returns plain text representation of this document.
String toPlainText() => _root.children.map((e) => e.toPlainText()).join(); String toPlainText([
Iterable<EmbedBuilder>? embedBuilders,
EmbedBuilder? unknownEmbedBuilder,
]) =>
_root.children
.map((e) => e.toPlainText(embedBuilders, unknownEmbedBuilder))
.join();
void _loadDocument(Delta doc) { void _loadDocument(Delta doc) {
if (doc.isEmpty) { if (doc.isEmpty) {

@ -1,5 +1,6 @@
import 'dart:collection'; import 'dart:collection';
import '../../../widgets/embeds.dart';
import '../style.dart'; import '../style.dart';
import 'leaf.dart'; import 'leaf.dart';
import 'line.dart'; import 'line.dart';
@ -103,7 +104,13 @@ abstract class Container<T extends Node?> extends Node {
} }
@override @override
String toPlainText() => children.map((child) => child.toPlainText()).join(); String toPlainText([
Iterable<EmbedBuilder>? embedBuilders,
EmbedBuilder? unknownEmbedBuilder,
]) =>
children
.map((e) => e.toPlainText(embedBuilders, unknownEmbedBuilder))
.join();
/// Content length of this node's children. /// Content length of this node's children.
/// ///

@ -1,5 +1,6 @@
import 'dart:math' as math; import 'dart:math' as math;
import '../../../widgets/embeds.dart';
import '../../quill_delta.dart'; import '../../quill_delta.dart';
import '../style.dart'; import '../style.dart';
import 'embeddable.dart'; import 'embeddable.dart';
@ -224,7 +225,11 @@ class Text extends Leaf {
String get value => _value as String; String get value => _value as String;
@override @override
String toPlainText() => value; String toPlainText([
Iterable<EmbedBuilder>? embedBuilders,
EmbedBuilder? unknownEmbedBuilder,
]) =>
value;
} }
/// An embed node inside of a line in a Quill document. /// An embed node inside of a line in a Quill document.
@ -257,7 +262,26 @@ class Embed extends Leaf {
// Embed nodes are represented as unicode object replacement character in // Embed nodes are represented as unicode object replacement character in
// plain text. // plain text.
@override @override
String toPlainText() => kObjectReplacementCharacter; String toPlainText([
Iterable<EmbedBuilder>? embedBuilders,
EmbedBuilder? unknownEmbedBuilder,
]) {
final builders = embedBuilders;
if (builders != null) {
for (final builder in builders) {
if (builder.key == value.type) {
return builder.toPlainText(this);
}
}
}
if (unknownEmbedBuilder != null) {
return unknownEmbedBuilder.toPlainText(this);
}
return Embed.kObjectReplacementCharacter;
}
@override @override
String toString() => '${super.toString()} ${value.type}'; String toString() => '${super.toString()} ${value.type}';

@ -2,6 +2,7 @@ import 'dart:math' as math;
import 'package:collection/collection.dart'; import 'package:collection/collection.dart';
import '../../../widgets/embeds.dart';
import '../../quill_delta.dart'; import '../../quill_delta.dart';
import '../../structs/offset_value.dart'; import '../../structs/offset_value.dart';
import '../attribute.dart'; import '../attribute.dart';
@ -65,7 +66,11 @@ class Line extends Container<Leaf?> {
} }
@override @override
String toPlainText() => '${super.toPlainText()}\n'; String toPlainText([
Iterable<EmbedBuilder>? embedBuilders,
EmbedBuilder? unknownEmbedBuilder,
]) =>
'${super.toPlainText(embedBuilders, unknownEmbedBuilder)}\n';
@override @override
String toString() { String toString() {

@ -1,5 +1,6 @@
import 'dart:collection'; import 'dart:collection';
import '../../../widgets/embeds.dart';
import '../../quill_delta.dart'; import '../../quill_delta.dart';
import '../attribute.dart'; import '../attribute.dart';
import '../style.dart'; import '../style.dart';
@ -109,7 +110,10 @@ abstract class Node extends LinkedListEntry<Node> {
Node newInstance(); Node newInstance();
String toPlainText(); String toPlainText([
Iterable<EmbedBuilder>? embedBuilders,
EmbedBuilder? unknownEmbedBuilder,
]);
Delta toDelta(); Delta toDelta();

@ -1,5 +1,6 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import '../../extensions.dart';
import '../models/documents/nodes/leaf.dart' as leaf; import '../models/documents/nodes/leaf.dart' as leaf;
import '../models/themes/quill_dialog_theme.dart'; import '../models/themes/quill_dialog_theme.dart';
import '../models/themes/quill_icon_theme.dart'; import '../models/themes/quill_icon_theme.dart';
@ -15,6 +16,8 @@ abstract class EmbedBuilder {
return WidgetSpan(child: widget); return WidgetSpan(child: widget);
} }
String toPlainText(Embed node) => Embed.kObjectReplacementCharacter;
Widget build( Widget build(
BuildContext context, BuildContext context,
QuillController controller, QuillController controller,

Loading…
Cancel
Save