From 506303a50d586ae256c2e8babfb7ece8d980bd87 Mon Sep 17 00:00:00 2001 From: Lucas Henrique Polazzo <43015129+LucazzP@users.noreply.github.com> Date: Thu, 21 Jul 2022 14:44:37 -0300 Subject: [PATCH] Added CustomBlockEmbed to the Readme (#879) * Added portuguese translations for image resizer * Added CustomBlockEmbed and customElementsEmbedBuilder * Added CustomBlockEmbed to the Readme * Formatted home page --- README.md | 124 ++++++++++++++++++++++++++++++- example/lib/pages/home_page.dart | 4 +- 2 files changed, 126 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index d91e3761..f9925032 100644 --- a/README.md +++ b/README.md @@ -164,13 +164,135 @@ Define `mobileWidth`, `mobileHeight`, `mobileMargin`, `mobileAlignment` as follo } ``` +## Custom Embed Blocks + +Sometimes you want to add some custom content inside your text, custom widgets inside of them. An example is adding notes to the text, or anything custom that you want to add in your text editor. + +The only thing that you need is to add a `CustomBlockEmbed` and map it into the `customElementsEmbedBuilder`, to transform the data inside of the Custom Block into a widget! + +Here is an example: + +Starting with the `CustomBlockEmbed`, here we extend it and add the methods that are useful for the 'Note' widget, that will be the `Document`, used by the `flutter_quill` to render the rich text. + +```dart +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)); +} +``` + +After that, we need to map this "notes" type into a widget. In that case, I used a `ListTile` with a text to show the plain text resume of the note, and the `onTap` function to edit the note. +Don't forget to add this method to the `QuillEditor` after that! + +```dart +Widget customElementsEmbedBuilder( + BuildContext context, + QuillController controller, + CustomBlockEmbed block, + bool readOnly, + void Function(GlobalKey videoContainerKey)? onVideoInit, +) { + switch (block.type) { + case 'notes': + final notes = NotesBlockEmbed(block.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), + ), + ), + ); + default: + return const SizedBox(); + } +} +``` + +And finally, we write the function to add/edit this note. The `showDialog` function shows the QuillEditor to edit the note, after the user ends the edition, we check if the document has something, and if it has, we add or edit the `NotesBlockEmbed` inside of a `BlockEmbed.custom` (this is a little detail that will not work if you don't pass the `CustomBlockEmbed` inside of a `BlockEmbed.custom`). + +```dart +Future _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, + ), + ), + ); + + if (quillEditorController.document.isEmpty()) return; + + final block = BlockEmbed.custom( + 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).item1; + controller.replaceText( + offset, 1, block, TextSelection.collapsed(offset: offset)); + } else { + controller.replaceText(index, length, block, null); + } +} +``` + +And voila, we have a custom widget inside of the rich text editor! + +

+ 1 +

+ +> For more info and a video example, see the [PR of this feature](https://github.com/singerdmx/flutter-quill/pull/877) + ## Translation + The package offers translations for the quill toolbar and editor, it will follow the system locale unless you set your own locale with: -``` + +```dart QuillToolbar(locale: Locale('fr'), ...) QuillEditor(locale: Locale('fr'), ...) ``` + Currently, translations are available for these 22 locales: + * `Locale('en')` * `Locale('ar')` * `Locale('de')` diff --git a/example/lib/pages/home_page.dart b/example/lib/pages/home_page.dart index 8c150b61..d8019f43 100644 --- a/example/lib/pages/home_page.dart +++ b/example/lib/pages/home_page.dart @@ -392,7 +392,9 @@ class _HomePageState extends State { } class NotesBlockEmbed extends CustomBlockEmbed { - const NotesBlockEmbed(String value) : super('notes', value); + const NotesBlockEmbed(String value) : super(noteType, value); + + static const String noteType = 'notes'; static NotesBlockEmbed fromDocument(Document document) => NotesBlockEmbed(jsonEncode(document.toDelta().toJson()));