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 '../universal_ui/universal_ui.dart';
import '../widgets/time_stamp_embed_widget.dart';
import 'read_only_page.dart';
enum _SelectionType {
@ -80,9 +81,24 @@ class _HomePageState extends State<HomePage> {
),
actions: [
IconButton(
onPressed: () => _addEditNote(context),
icon: const Icon(Icons.note_add),
onPressed: () => _insertTimeStamp(
_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(
@ -188,7 +204,7 @@ class _HomePageState extends State<HomePage> {
),
embedBuilders: [
...FlutterQuillEmbeds.builders(),
NotesEmbedBuilder(addEditNote: _addEditNote)
TimeStampEmbedBuilderWidget()
],
);
if (kIsWeb) {
@ -220,7 +236,7 @@ class _HomePageState extends State<HomePage> {
),
embedBuilders: [
...defaultEmbedBuildersWeb,
NotesEmbedBuilder(addEditNote: _addEditNote),
TimeStampEmbedBuilderWidget()
]);
}
var toolbar = QuillToolbar.basic(
@ -433,99 +449,41 @@ class _HomePageState extends State<HomePage> {
return file.path.toString();
}
Future<void> _addEditNote(BuildContext context, {Document? document}) async {
final isEditing = document != null;
final quillEditorController = QuillController(
document: document ?? Document(),
selection: const TextSelection.collapsed(offset: 0),
);
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,
),
static void _insertTimeStamp(QuillController controller, String string) {
controller.document.insert(controller.selection.extentOffset, '\n');
controller.updateSelection(
TextSelection.collapsed(
offset: controller.selection.extentOffset + 1,
),
ChangeSource.LOCAL,
);
if (quillEditorController.document.isEmpty()) return;
final block = BlockEmbed.custom(
NotesBlockEmbed.fromDocument(quillEditorController.document),
controller.document.insert(
controller.selection.extentOffset,
TimeStampEmbed(string),
);
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 {
NotesEmbedBuilder({required this.addEditNote});
Future<void> Function(BuildContext context, {Document? document}) addEditNote;
controller.updateSelection(
TextSelection.collapsed(
offset: controller.selection.extentOffset + 1,
),
ChangeSource.LOCAL,
);
@override
String get key => 'notes';
controller.document.insert(controller.selection.extentOffset, ' ');
controller.updateSelection(
TextSelection.collapsed(
offset: controller.selection.extentOffset + 1,
),
ChangeSource.LOCAL,
);
@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),
onTap: () => addEditNote(context, document: notes),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
side: const BorderSide(color: Colors.grey),
),
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 '../../widgets/embeds.dart';
import '../quill_delta.dart';
import '../rules/rule.dart';
import '../structs/doc_change.dart';
@ -349,7 +350,13 @@ class 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) {
if (doc.isEmpty) {

@ -1,5 +1,6 @@
import 'dart:collection';
import '../../../widgets/embeds.dart';
import '../style.dart';
import 'leaf.dart';
import 'line.dart';
@ -103,7 +104,13 @@ abstract class Container<T extends Node?> extends Node {
}
@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.
///

@ -1,5 +1,6 @@
import 'dart:math' as math;
import '../../../widgets/embeds.dart';
import '../../quill_delta.dart';
import '../style.dart';
import 'embeddable.dart';
@ -224,7 +225,11 @@ class Text extends Leaf {
String get value => _value as String;
@override
String toPlainText() => value;
String toPlainText([
Iterable<EmbedBuilder>? embedBuilders,
EmbedBuilder? unknownEmbedBuilder,
]) =>
value;
}
/// 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
// plain text.
@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
String toString() => '${super.toString()} ${value.type}';

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

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

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

Loading…
Cancel
Save