From c67c96645751038721c2a4b76fcf31f8f54457c5 Mon Sep 17 00:00:00 2001 From: singerdmx Date: Mon, 15 Feb 2021 23:04:20 -0800 Subject: [PATCH 01/22] Update README --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index e0c87ee0..754b9a43 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,9 @@ This library is a WYSIWYG editor built for the modern mobile platform only and w https://pub.dev/packages/flutter_quill +This library use [Quill] as an internal data format. +Use `_controller.document.toDelta()` to extract it or use `_controller.document.toPlainText()` for plain text. + Default branch `master` is on channel `master`. To use channel `stable`, switch to branch `stable`. Branch `master` on channel `master` supports web. To run the app on web do the following: 1) Change flutter channel to master using `flutter channel master`, followed by `flutter upgrade`. @@ -30,7 +33,7 @@ For web development, [ReactQuill] is recommended to use for compatibility. One client and affiliated collaborator of **[FlutterQuill]** is Bullet Journal App: https://bulletjournal.us/home/index.html -[Quill]: https://quilljs.com +[Quill]: https://quilljs.com/docs/formats [Flutter]: https://github.com/flutter/flutter [FlutterQuill]: https://pub.dev/packages/flutter_quill [ReactQuill]: https://github.com/zenoamaro/react-quill From 066f4d29fc0026ad6aff9fdee9f4239b578c31cb Mon Sep 17 00:00:00 2001 From: Rishi Raj Singh <49035175+rish07@users.noreply.github.com> Date: Tue, 16 Feb 2021 21:45:58 +0530 Subject: [PATCH 02/22] Fix image size issue (#24) --- app/lib/main.dart | 1 + app/lib/pages/home_page.dart | 26 ++++---- app/pubspec.lock | 49 +++++++++++++++ lib/widgets/FakeUi.dart | 4 ++ lib/widgets/RealUi.dart | 9 +++ lib/widgets/editor.dart | 60 ++++++++++++------- lib/widgets/responsive_widget.dart | 43 +++++++++++++ pubspec.lock | 96 +++++++++++++++++++++++------- pubspec.yaml | 1 + 9 files changed, 237 insertions(+), 52 deletions(-) create mode 100644 lib/widgets/FakeUi.dart create mode 100644 lib/widgets/RealUi.dart create mode 100644 lib/widgets/responsive_widget.dart diff --git a/app/lib/main.dart b/app/lib/main.dart index 77622559..f3ec0666 100644 --- a/app/lib/main.dart +++ b/app/lib/main.dart @@ -4,6 +4,7 @@ import 'package:flutter/material.dart'; import 'pages/home_page.dart'; void main() { + WidgetsFlutterBinding.ensureInitialized(); runApp(MyApp()); } diff --git a/app/lib/pages/home_page.dart b/app/lib/pages/home_page.dart index 3663543f..422d0954 100644 --- a/app/lib/pages/home_page.dart +++ b/app/lib/pages/home_page.dart @@ -89,11 +89,11 @@ class _HomePageState extends State { } Widget _buildWelcomeEditor(BuildContext context) { - return Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - Expanded( - child: Container( + return SafeArea( + child: Stack( + children: [ + Container( + height: MediaQuery.of(context).size.height * 0.88, color: Colors.white, padding: const EdgeInsets.only(left: 16.0, right: 16.0), child: QuillEditor( @@ -120,13 +120,15 @@ class _HomePageState extends State { sizeSmall: TextStyle(fontSize: 9.0)), ), ), - ), - Container( - child: QuillToolbar.basic( - controller: _controller, - uploadFileCallback: _fakeUploadImageCallBack), - ) - ], + Container( + padding: + EdgeInsets.only(top: MediaQuery.of(context).size.height * 0.9), + child: QuillToolbar.basic( + controller: _controller, + uploadFileCallback: _fakeUploadImageCallBack), + ) + ], + ), ); } diff --git a/app/pubspec.lock b/app/pubspec.lock index 25012d30..f4e16a57 100644 --- a/app/pubspec.lock +++ b/app/pubspec.lock @@ -43,6 +43,27 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.15.0" + convert: + dependency: transitive + description: + name: convert + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.1" + crypto: + dependency: transitive + description: + name: crypto + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.5" + csslib: + dependency: transitive + description: + name: csslib + url: "https://pub.dartlang.org" + source: hosted + version: "0.16.2" cupertino_icons: dependency: "direct main" description: @@ -93,6 +114,13 @@ packages: description: flutter source: sdk version: "0.0.0" + html: + dependency: transitive + description: + name: html + url: "https://pub.dartlang.org" + source: hosted + version: "0.14.0+4" http: dependency: transitive description: @@ -252,6 +280,20 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.3.0" + universal_html: + dependency: transitive + description: + name: universal_html + url: "https://pub.dartlang.org" + source: hosted + version: "1.2.4" + universal_io: + dependency: transitive + description: + name: universal_io + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.2" url_launcher: dependency: transitive description: @@ -301,6 +343,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.1.0" + zone_local: + dependency: transitive + description: + name: zone_local + url: "https://pub.dartlang.org" + source: hosted + version: "0.1.2" sdks: dart: ">=2.12.0-0.0 <3.0.0" flutter: ">=1.22.0" diff --git a/lib/widgets/FakeUi.dart b/lib/widgets/FakeUi.dart new file mode 100644 index 00000000..bc9799af --- /dev/null +++ b/lib/widgets/FakeUi.dart @@ -0,0 +1,4 @@ +// ignore: camel_case_types +class platformViewRegistry { + static registerViewFactory(String viewId, dynamic cb) {} +} diff --git a/lib/widgets/RealUi.dart b/lib/widgets/RealUi.dart new file mode 100644 index 00000000..c2b8ea23 --- /dev/null +++ b/lib/widgets/RealUi.dart @@ -0,0 +1,9 @@ +import 'dart:ui' as ui; + +// ignore: camel_case_types +class platformViewRegistry { + static registerViewFactory(String viewId, dynamic cb) { + // ignore:undefined_prefixed_name + ui.platformViewRegistry.registerViewFactory(viewId, cb); + } +} diff --git a/lib/widgets/editor.dart b/lib/widgets/editor.dart index 6a388ed8..018ef0b2 100644 --- a/lib/widgets/editor.dart +++ b/lib/widgets/editor.dart @@ -1,7 +1,5 @@ -import 'dart:html' as html; -import 'dart:io'; +import 'dart:io' as io; import 'dart:math' as math; -import 'dart:ui' as ui; import 'package:flutter/cupertino.dart'; import 'package:flutter/foundation.dart'; @@ -19,9 +17,12 @@ import 'package:flutter_quill/models/documents/nodes/line.dart'; import 'package:flutter_quill/models/documents/nodes/node.dart'; import 'package:flutter_quill/widgets/image.dart'; import 'package:flutter_quill/widgets/raw_editor.dart'; +import 'package:flutter_quill/widgets/responsive_widget.dart'; import 'package:flutter_quill/widgets/text_selection.dart'; +import 'package:universal_html/prefer_universal/html.dart' as html; import 'package:url_launcher/url_launcher.dart'; +import 'FakeUi.dart' if (dart.library.html) 'RealUi.dart' as ui; import 'box.dart'; import 'controller.dart'; import 'cursor.dart'; @@ -79,25 +80,43 @@ abstract class RenderAbstractEditor { Widget _defaultEmbedBuilder(BuildContext context, leaf.Embed node) { switch (node.value.type) { case 'image': - if (kIsWeb) { - String imageUrl = node.value.data; + String imageUrl = node.value.data; + return imageUrl.startsWith('http') + ? Image.network(imageUrl) + : Image.file(io.File(imageUrl)); + default: + throw UnimplementedError( + 'Embeddable type "${node.value.type}" is not supported by default embed ' + 'builder of QuillEditor. You must pass your own builder function to ' + 'embedBuilder property of QuillEditor or QuillField widgets.'); + } +} - ui.platformViewRegistry.registerViewFactory( - imageUrl, - (int viewId) => html.ImageElement()..src = imageUrl, - ); - return Container( - constraints: BoxConstraints(maxWidth: 300), - height: MediaQuery.of(context).size.height, +Widget _defaultEmbedBuilderWeb(BuildContext context, leaf.Embed node) { + switch (node.value.type) { + case 'image': + String imageUrl = node.value.data; + Size size = MediaQuery.of(context).size; + ui.platformViewRegistry.registerViewFactory( + imageUrl, + (int viewId) => html.ImageElement()..src = imageUrl, + ); + return Padding( + padding: EdgeInsets.only( + right: ResponsiveWidget.isMediumScreen(context) + ? size.width * 0.5 + : (ResponsiveWidget.isLargeScreen(context)) + ? size.width * 0.75 + : size.width * 0.2, + ), + child: SizedBox( + height: MediaQuery.of(context).size.height * 0.45, child: HtmlElementView( viewType: imageUrl, ), - ); - } - String imageUrl = node.value.data; - return imageUrl.startsWith('http') - ? Image.network(imageUrl) - : Image.file(File(imageUrl)); + ), + ); + default: throw UnimplementedError( 'Embeddable type "${node.value.type}" is not supported by default embed ' @@ -144,7 +163,8 @@ class QuillEditor extends StatefulWidget { this.keyboardAppearance = Brightness.light, this.scrollPhysics, this.onLaunchUrl, - this.embedBuilder = _defaultEmbedBuilder}) + this.embedBuilder = + kIsWeb ? _defaultEmbedBuilderWeb : _defaultEmbedBuilder}) : assert(controller != null), assert(scrollController != null), assert(scrollable != null), @@ -383,7 +403,7 @@ class _QuillEditorSelectionGestureDetectorBuilder builder: (context) => ImageTapWrapper( imageProvider: imageUrl.startsWith('http') ? NetworkImage(imageUrl) - : FileImage(File(blockEmbed.data))), + : FileImage(io.File(blockEmbed.data))), ), ); } diff --git a/lib/widgets/responsive_widget.dart b/lib/widgets/responsive_widget.dart new file mode 100644 index 00000000..a047deab --- /dev/null +++ b/lib/widgets/responsive_widget.dart @@ -0,0 +1,43 @@ +import 'package:flutter/material.dart'; + +class ResponsiveWidget extends StatelessWidget { + final Widget largeScreen; + final Widget mediumScreen; + final Widget smallScreen; + + const ResponsiveWidget( + {Key key, + @required this.largeScreen, + this.mediumScreen, + this.smallScreen}) + : super(key: key); + + static bool isSmallScreen(BuildContext context) { + return MediaQuery.of(context).size.width < 800; + } + + static bool isLargeScreen(BuildContext context) { + return MediaQuery.of(context).size.width > 1200; + } + + static bool isMediumScreen(BuildContext context) { + return MediaQuery.of(context).size.width >= 800 && + MediaQuery.of(context).size.width <= 1200; + } + + @override + Widget build(BuildContext context) { + return LayoutBuilder( + builder: (context, constraints) { + if (constraints.maxWidth > 1200) { + return largeScreen; + } else if (constraints.maxWidth <= 1200 && + constraints.maxWidth >= 800) { + return mediumScreen ?? largeScreen; + } else { + return smallScreen ?? largeScreen; + } + }, + ); + } +} diff --git a/pubspec.lock b/pubspec.lock index 09ae8cdc..4afa0337 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -7,49 +7,70 @@ packages: name: async url: "https://pub.dartlang.org" source: hosted - version: "2.5.0-nullsafety.1" + version: "2.5.0" boolean_selector: dependency: transitive description: name: boolean_selector url: "https://pub.dartlang.org" source: hosted - version: "2.1.0-nullsafety.1" + version: "2.1.0" characters: dependency: transitive description: name: characters url: "https://pub.dartlang.org" source: hosted - version: "1.1.0-nullsafety.3" + version: "1.1.0" charcode: dependency: transitive description: name: charcode url: "https://pub.dartlang.org" source: hosted - version: "1.2.0-nullsafety.1" + version: "1.2.0" clock: dependency: transitive description: name: clock url: "https://pub.dartlang.org" source: hosted - version: "1.1.0-nullsafety.1" + version: "1.1.0" collection: dependency: "direct main" description: name: collection url: "https://pub.dartlang.org" source: hosted - version: "1.15.0-nullsafety.3" + version: "1.15.0" + convert: + dependency: transitive + description: + name: convert + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.1" + crypto: + dependency: transitive + description: + name: crypto + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.5" + csslib: + dependency: transitive + description: + name: csslib + url: "https://pub.dartlang.org" + source: hosted + version: "0.16.2" fake_async: dependency: transitive description: name: fake_async url: "https://pub.dartlang.org" source: hosted - version: "1.2.0-nullsafety.1" + version: "1.2.0" flutter: dependency: "direct main" description: flutter @@ -79,6 +100,13 @@ packages: description: flutter source: sdk version: "0.0.0" + html: + dependency: transitive + description: + name: html + url: "https://pub.dartlang.org" + source: hosted + version: "0.14.0+4" http: dependency: transitive description: @@ -107,27 +135,34 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.1.1" + js: + dependency: transitive + description: + name: js + url: "https://pub.dartlang.org" + source: hosted + version: "0.6.3" matcher: dependency: transitive description: name: matcher url: "https://pub.dartlang.org" source: hosted - version: "0.12.10-nullsafety.1" + version: "0.12.10" meta: dependency: transitive description: name: meta url: "https://pub.dartlang.org" source: hosted - version: "1.3.0-nullsafety.3" + version: "1.3.0" path: dependency: transitive description: name: path url: "https://pub.dartlang.org" source: hosted - version: "1.8.0-nullsafety.1" + version: "1.8.0" pedantic: dependency: transitive description: @@ -181,42 +216,42 @@ packages: name: source_span url: "https://pub.dartlang.org" source: hosted - version: "1.8.0-nullsafety.2" + version: "1.8.0" stack_trace: dependency: transitive description: name: stack_trace url: "https://pub.dartlang.org" source: hosted - version: "1.10.0-nullsafety.1" + version: "1.10.0" stream_channel: dependency: transitive description: name: stream_channel url: "https://pub.dartlang.org" source: hosted - version: "2.1.0-nullsafety.1" + version: "2.1.0" string_scanner: dependency: transitive description: name: string_scanner url: "https://pub.dartlang.org" source: hosted - version: "1.1.0-nullsafety.1" + version: "1.1.0" term_glyph: dependency: transitive description: name: term_glyph url: "https://pub.dartlang.org" source: hosted - version: "1.2.0-nullsafety.1" + version: "1.2.0" test_api: dependency: transitive description: name: test_api url: "https://pub.dartlang.org" source: hosted - version: "0.2.19-nullsafety.2" + version: "0.2.19" tuple: dependency: "direct main" description: @@ -230,7 +265,21 @@ packages: name: typed_data url: "https://pub.dartlang.org" source: hosted - version: "1.3.0-nullsafety.3" + version: "1.3.0" + universal_html: + dependency: "direct main" + description: + name: universal_html + url: "https://pub.dartlang.org" + source: hosted + version: "1.2.4" + universal_io: + dependency: transitive + description: + name: universal_io + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.2" url_launcher: dependency: "direct main" description: @@ -279,7 +328,14 @@ packages: name: vector_math url: "https://pub.dartlang.org" source: hosted - version: "2.1.0-nullsafety.3" + version: "2.1.0" + zone_local: + dependency: transitive + description: + name: zone_local + url: "https://pub.dartlang.org" + source: hosted + version: "0.1.2" sdks: - dart: ">=2.10.0-110 <2.11.0" - flutter: ">=1.22.0 <2.0.0" + dart: ">=2.12.0-0.0 <3.0.0" + flutter: ">=1.22.0" diff --git a/pubspec.yaml b/pubspec.yaml index fb373ad1..d9cff81e 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -20,6 +20,7 @@ dependencies: flutter_colorpicker: ^0.3.4 image_picker: ^0.6.7+17 photo_view: ^0.10.3 + universal_html: ^1.2.1 dev_dependencies: flutter_test: From fffc4dba6389e32e6ecbfdaf8afdf67be9762768 Mon Sep 17 00:00:00 2001 From: Arjan Aswal Date: Tue, 16 Feb 2021 23:02:35 +0530 Subject: [PATCH 03/22] Change baseSpacing for paragraph attribute --- lib/widgets/default_styles.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/widgets/default_styles.dart b/lib/widgets/default_styles.dart index 861bb3cd..cd5eb9fe 100644 --- a/lib/widgets/default_styles.dart +++ b/lib/widgets/default_styles.dart @@ -135,7 +135,7 @@ class DefaultStyles { Tuple2(0.0, 0.0), null), paragraph: DefaultTextBlockStyle( - baseStyle, baseSpacing, Tuple2(0.0, 0.0), null), + baseStyle, Tuple2(0.0, 0.0), Tuple2(0.0, 0.0), null), bold: TextStyle(fontWeight: FontWeight.bold), italic: TextStyle(fontStyle: FontStyle.italic), underline: TextStyle(decoration: TextDecoration.underline), From 9cf6bb94f960c4d3c1a0a0b5c3a03b7cbf96818e Mon Sep 17 00:00:00 2001 From: singerdmx Date: Tue, 16 Feb 2021 09:41:03 -0800 Subject: [PATCH 04/22] Change baseSpacing to Tuple2(6.0, 0) --- lib/widgets/default_styles.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/widgets/default_styles.dart b/lib/widgets/default_styles.dart index cd5eb9fe..cef0011b 100644 --- a/lib/widgets/default_styles.dart +++ b/lib/widgets/default_styles.dart @@ -86,7 +86,7 @@ class DefaultStyles { fontSize: 16.0, height: 1.3, ); - Tuple2 baseSpacing = Tuple2(6.0, 10); + Tuple2 baseSpacing = Tuple2(6.0, 0); String fontFamily; switch (themeData.platform) { case TargetPlatform.iOS: From 20ab74748fee38b3aba36911377ab20a953fe699 Mon Sep 17 00:00:00 2001 From: singerdmx Date: Tue, 16 Feb 2021 16:44:42 -0800 Subject: [PATCH 05/22] Revert home page change --- app/lib/pages/home_page.dart | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/app/lib/pages/home_page.dart b/app/lib/pages/home_page.dart index 422d0954..3663543f 100644 --- a/app/lib/pages/home_page.dart +++ b/app/lib/pages/home_page.dart @@ -89,11 +89,11 @@ class _HomePageState extends State { } Widget _buildWelcomeEditor(BuildContext context) { - return SafeArea( - child: Stack( - children: [ - Container( - height: MediaQuery.of(context).size.height * 0.88, + return Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Expanded( + child: Container( color: Colors.white, padding: const EdgeInsets.only(left: 16.0, right: 16.0), child: QuillEditor( @@ -120,15 +120,13 @@ class _HomePageState extends State { sizeSmall: TextStyle(fontSize: 9.0)), ), ), - Container( - padding: - EdgeInsets.only(top: MediaQuery.of(context).size.height * 0.9), - child: QuillToolbar.basic( - controller: _controller, - uploadFileCallback: _fakeUploadImageCallBack), - ) - ], - ), + ), + Container( + child: QuillToolbar.basic( + controller: _controller, + uploadFileCallback: _fakeUploadImageCallBack), + ) + ], ); } From 556dd2085a2c60ab5f7b8f1b24a22bf60b2c805b Mon Sep 17 00:00:00 2001 From: Xin Yao Date: Tue, 16 Feb 2021 19:02:32 -0800 Subject: [PATCH 06/22] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 754b9a43..3b94eaaf 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ This library is a WYSIWYG editor built for the modern mobile platform only and w https://pub.dev/packages/flutter_quill -This library use [Quill] as an internal data format. +This library uses [Quill] as an internal data format. Use `_controller.document.toDelta()` to extract it or use `_controller.document.toPlainText()` for plain text. Default branch `master` is on channel `master`. To use channel `stable`, switch to branch `stable`. From caf6db8416248e650648e77f656aac9453a23cdb Mon Sep 17 00:00:00 2001 From: singerdmx Date: Thu, 18 Feb 2021 21:50:03 -0800 Subject: [PATCH 07/22] Reuse textSpan --- lib/widgets/text_line.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/widgets/text_line.dart b/lib/widgets/text_line.dart index 53bb07f8..6d7efa6b 100644 --- a/lib/widgets/text_line.dart +++ b/lib/widgets/text_line.dart @@ -48,7 +48,7 @@ class TextLine extends StatelessWidget { StrutStyle.fromTextStyle(textSpan.style, forceStrutHeight: true); final textAlign = _getTextAlign(); RichText child = RichText( - text: _buildTextSpan(context), + text: textSpan, textAlign: textAlign, textDirection: textDirection, strutStyle: strutStyle, From 0bae977188adc76decb6030a2defed72470c22b8 Mon Sep 17 00:00:00 2001 From: li3317 Date: Fri, 19 Feb 2021 17:05:52 -0500 Subject: [PATCH 08/22] enable autocorrect --- lib/widgets/raw_editor.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/widgets/raw_editor.dart b/lib/widgets/raw_editor.dart index 3ff24e55..6ae948ff 100644 --- a/lib/widgets/raw_editor.dart +++ b/lib/widgets/raw_editor.dart @@ -374,7 +374,7 @@ class RawEditorState extends EditorState inputType: TextInputType.multiline, readOnly: widget.readOnly, obscureText: false, - autocorrect: false, + autocorrect: true, inputAction: TextInputAction.newline, keyboardAppearance: widget.keyboardAppearance, textCapitalization: widget.textCapitalization, From ff3563ea6e7b021b6352573af05519b77ddb7aed Mon Sep 17 00:00:00 2001 From: singerdmx Date: Fri, 19 Feb 2021 22:04:42 -0800 Subject: [PATCH 09/22] Upgrade image_picker --- CHANGELOG.md | 5 ++++- app/pubspec.lock | 2 +- pubspec.lock | 2 +- pubspec.yaml | 4 ++-- 4 files changed, 8 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 45a82501..5bfda437 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -78,4 +78,7 @@ * Support display local image besides network image. ## [0.2.8] -* Support display local image besides network image in stable branch. \ No newline at end of file +* Support display local image besides network image in stable branch. + +## [0.2.9] +* Update TextInputConfiguration autocorrect to true. \ No newline at end of file diff --git a/app/pubspec.lock b/app/pubspec.lock index f4e16a57..66f4b1e0 100644 --- a/app/pubspec.lock +++ b/app/pubspec.lock @@ -103,7 +103,7 @@ packages: path: ".." relative: true source: path - version: "0.2.8" + version: "0.2.9" flutter_test: dependency: "direct dev" description: flutter diff --git a/pubspec.lock b/pubspec.lock index 4afa0337..25975c15 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -127,7 +127,7 @@ packages: name: image_picker url: "https://pub.dartlang.org" source: hosted - version: "0.6.7+17" + version: "0.6.7+22" image_picker_platform_interface: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index d9cff81e..09d03a06 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: flutter_quill description: One client and affiliated collaborator of Flutter Quill is Bullet Journal App. -version: 0.2.8 +version: 0.2.9 #author: bulletjournal homepage: https://bulletjournal.us/home/index.html repository: https://github.com/singerdmx/flutter-quill.git @@ -18,7 +18,7 @@ dependencies: tuple: ^1.0.3 url_launcher: ^5.7.10 flutter_colorpicker: ^0.3.4 - image_picker: ^0.6.7+17 + image_picker: ^0.6.7+22 photo_view: ^0.10.3 universal_html: ^1.2.1 From 59410649db36eef01c17a9f2a757251d9bb1a94d Mon Sep 17 00:00:00 2001 From: Jon Mountjoy Date: Sat, 20 Feb 2021 09:26:18 +0000 Subject: [PATCH 10/22] More docs (#33) --- README.md | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 58 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 3b94eaaf..4b03b0ac 100644 --- a/README.md +++ b/README.md @@ -6,17 +6,72 @@ # FlutterQuill -Rich text editor and a [Quill] component for [Flutter]. +FlutterQuill is a rich text editor and a [Quill] component for [Flutter]. -This library is a WYSIWYG editor built for the modern mobile platform only and web is under development. You can join [Slack Group] for discussion. +This library is a WYSIWYG editor built for the modern mobile platform, with web compatibility under development. You can join our [Slack Group] for discussion. https://pub.dev/packages/flutter_quill +## Usage + +See the `example` directory for a minimal example of how to use FlutterQuill. You typically just need to instantiate a controller: + +``` +QuillController _controller = QuillController.basic(); +``` + +and then embed the toolbar and the editor, within your app. For example: + +```dart +Column( + children: [ + QuillToolbar.basic( + controller: _controller, uploadFileCallback: _uploadImageCallBack), + Expanded( + child: Container( + child: QuillEditor.basic( + controller: _controller, + readOnly: false, // true for view only mode + ), + ), + ) + ], +) +``` + +## Input / Output + This library uses [Quill] as an internal data format. -Use `_controller.document.toDelta()` to extract it or use `_controller.document.toPlainText()` for plain text. + +* Use `_controller.document.toDelta()` to extract the deltas. +* Use `_controller.document.toPlainText()` to extract plain text. + +FlutterQuill provides some JSON serialisation support, so that you can save and open documents. To save a document as JSON, do something like the following: + +``` +var json = jsonEncode(_controller.document.toDelta().toJson()); +``` + +You can then write this to storage. + +To open a FlutterQuill editor with an existing JSON representation that you've previously stored, you can do something like this: + +``` +var myJSON = jsonDecode(incomingJSONText); +_controller = QuillController( + document: Document.fromJson(myJSON), + selection: TextSelection.collapsed(offset: 0)); +``` + +## Configuration + +The `QuillToolbar` class lets you customise which formating options are available. To prevent the image uploading widget from appearing, set `uploadFileCallback` to null. + +## Web Default branch `master` is on channel `master`. To use channel `stable`, switch to branch `stable`. Branch `master` on channel `master` supports web. To run the app on web do the following: + 1) Change flutter channel to master using `flutter channel master`, followed by `flutter upgrade`. 2) Enable web using `flutter config --enable-web` and restart the IDE. 3) Upon successful execution of step 1 and 2 you should see `Chrome` as one of the devices which you run `flutter devices`. From a3ee421d1aab53a676d19fb31efb78a3eb5aa98e Mon Sep 17 00:00:00 2001 From: singerdmx Date: Sat, 20 Feb 2021 01:49:47 -0800 Subject: [PATCH 11/22] Add isEmpty method for Document class --- lib/models/documents/document.dart | 14 ++++++++ lib/widgets/raw_editor.dart | 55 +++++++++++++++++------------- 2 files changed, 46 insertions(+), 23 deletions(-) diff --git a/lib/models/documents/document.dart b/lib/models/documents/document.dart index bcfd5152..93585897 100644 --- a/lib/models/documents/document.dart +++ b/lib/models/documents/document.dart @@ -237,6 +237,20 @@ class Document { _root.remove(node); } } + + bool isEmpty() { + if (root.children.length != 1) { + return false; + } + + final Node node = root.children.first; + if (!node.isLast) { + return false; + } + + Delta delta = node.toDelta(); + return delta.length == 1 && delta.first.data == '\n'; + } } enum ChangeSource { diff --git a/lib/widgets/raw_editor.dart b/lib/widgets/raw_editor.dart index 6ae948ff..891bff86 100644 --- a/lib/widgets/raw_editor.dart +++ b/lib/widgets/raw_editor.dart @@ -503,13 +503,15 @@ class RawEditorState extends EditorState _focusAttachment.reparent(); super.build(context); + Document _doc = widget.controller.document; + Widget child = CompositedTransformTarget( link: _toolbarLayerLink, child: Semantics( child: _Editor( key: _editorKey, - children: _buildChildren(context), - document: widget.controller.document, + children: _buildChildren(_doc, context), + document: _doc, selection: widget.controller.selection, hasFocus: _hasFocus, textDirection: _textDirection, @@ -562,30 +564,13 @@ class RawEditorState extends EditorState requestKeyboard(); } - _buildChildren(BuildContext context) { + _buildChildren(Document doc, BuildContext context) { final result = []; Map indentLevelCounts = {}; - for (Node node in widget.controller.document.root.children) { + for (Node node in doc.root.children) { if (node is Line) { - TextLine textLine = TextLine( - line: node, - textDirection: _textDirection, - embedBuilder: widget.embedBuilder, - styles: _styles, - ); - EditableTextLine editableTextLine = EditableTextLine( - node, - null, - textLine, - 0, - _getVerticalSpacingForLine(node, _styles), - _textDirection, - widget.controller.selection, - widget.selectionColor, - widget.enableInteractiveSelection, - _hasFocus, - MediaQuery.of(context).devicePixelRatio, - _cursorCont); + EditableTextLine editableTextLine = + _getEditableTextLineFromNode(node, context); result.add(editableTextLine); } else if (node is Block) { Map attrs = node.style.attributes; @@ -612,6 +597,30 @@ class RawEditorState extends EditorState return result; } + EditableTextLine _getEditableTextLineFromNode( + Line node, BuildContext context) { + TextLine textLine = TextLine( + line: node, + textDirection: _textDirection, + embedBuilder: widget.embedBuilder, + styles: _styles, + ); + EditableTextLine editableTextLine = EditableTextLine( + node, + null, + textLine, + 0, + _getVerticalSpacingForLine(node, _styles), + _textDirection, + widget.controller.selection, + widget.selectionColor, + widget.enableInteractiveSelection, + _hasFocus, + MediaQuery.of(context).devicePixelRatio, + _cursorCont); + return editableTextLine; + } + Tuple2 _getVerticalSpacingForLine( Line line, DefaultStyles defaultStyles) { Map attrs = line.style.attributes; From f4f81d5b1df074f47e21fa8ffada6ccff8504ef2 Mon Sep 17 00:00:00 2001 From: pengw00 Date: Sat, 20 Feb 2021 16:47:06 -0600 Subject: [PATCH 12/22] Bump Version to 0.2.11 --- CHANGELOG.md | 8 +++++++- pubspec.yaml | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5bfda437..b3a4b172 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -81,4 +81,10 @@ * Support display local image besides network image in stable branch. ## [0.2.9] -* Update TextInputConfiguration autocorrect to true. \ No newline at end of file +* Update TextInputConfiguration autocorrect to true. + +## [0.2.10] +* Update TextInputConfiguration autocorrect to true in stable branch. + +## [0.2.11] +* Fix static analysis error. \ No newline at end of file diff --git a/pubspec.yaml b/pubspec.yaml index 09d03a06..b601cff1 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: flutter_quill description: One client and affiliated collaborator of Flutter Quill is Bullet Journal App. -version: 0.2.9 +version: 0.2.11 #author: bulletjournal homepage: https://bulletjournal.us/home/index.html repository: https://github.com/singerdmx/flutter-quill.git From 7d4bfa67a8e33d9ac73386dbb0fe6e966d797468 Mon Sep 17 00:00:00 2001 From: li3317 Date: Sat, 20 Feb 2021 22:26:37 -0500 Subject: [PATCH 13/22] support placeholder for empty content --- app/lib/pages/home_page.dart | 1 + lib/models/documents/attribute.dart | 11 ++++++++++- lib/models/documents/document.dart | 2 +- lib/widgets/default_styles.dart | 12 ++++++++++++ lib/widgets/editor.dart | 6 ++++++ lib/widgets/raw_editor.dart | 10 ++++++++++ lib/widgets/text_line.dart | 5 +++++ 7 files changed, 45 insertions(+), 2 deletions(-) diff --git a/app/lib/pages/home_page.dart b/app/lib/pages/home_page.dart index 3663543f..dafa4859 100644 --- a/app/lib/pages/home_page.dart +++ b/app/lib/pages/home_page.dart @@ -103,6 +103,7 @@ class _HomePageState extends State { focusNode: _focusNode, autoFocus: false, readOnly: false, + placeholder: 'Add content', enableInteractiveSelection: true, expands: false, padding: EdgeInsets.zero, diff --git a/lib/models/documents/attribute.dart b/lib/models/documents/attribute.dart index d7865e7d..7b363bed 100644 --- a/lib/models/documents/attribute.dart +++ b/lib/models/documents/attribute.dart @@ -24,6 +24,7 @@ class Attribute { Attribute.link.key: Attribute.link, Attribute.color.key: Attribute.color, Attribute.background.key: Attribute.background, + Attribute.placeholder.key: Attribute.placeholder, Attribute.header.key: Attribute.header, Attribute.indent.key: Attribute.indent, Attribute.align.key: Attribute.align, @@ -53,6 +54,8 @@ class Attribute { static final BackgroundAttribute background = BackgroundAttribute(null); + static final PlaceholderAttribute placeholder = PlaceholderAttribute(); + static final HeaderAttribute header = HeaderAttribute(); static final IndentAttribute indent = IndentAttribute(); @@ -78,7 +81,8 @@ class Attribute { Attribute.strikeThrough.key, Attribute.link.key, Attribute.color.key, - Attribute.background.key + Attribute.background.key, + Attribute.placeholder.key, }; static final Set blockKeys = { @@ -222,6 +226,11 @@ class BackgroundAttribute extends Attribute { : super('background', AttributeScope.INLINE, val); } +/// This is custom attribute for hint +class PlaceholderAttribute extends Attribute { + PlaceholderAttribute() : super('placeholder', AttributeScope.INLINE, true); +} + class HeaderAttribute extends Attribute { HeaderAttribute({int level}) : super('header', AttributeScope.BLOCK, level); } diff --git a/lib/models/documents/document.dart b/lib/models/documents/document.dart index 93585897..f41ee0bd 100644 --- a/lib/models/documents/document.dart +++ b/lib/models/documents/document.dart @@ -249,7 +249,7 @@ class Document { } Delta delta = node.toDelta(); - return delta.length == 1 && delta.first.data == '\n'; + return delta.length == 1 && delta.first.data == '\n' && delta.first.key == 'insert'; } } diff --git a/lib/widgets/default_styles.dart b/lib/widgets/default_styles.dart index cef0011b..4cad7bbb 100644 --- a/lib/widgets/default_styles.dart +++ b/lib/widgets/default_styles.dart @@ -54,6 +54,7 @@ class DefaultStyles { final TextStyle sizeLarge; // 'large' final TextStyle sizeHuge; // 'huge' final TextStyle link; + final DefaultTextBlockStyle placeHolder; final DefaultTextBlockStyle lists; final DefaultTextBlockStyle quote; final DefaultTextBlockStyle code; @@ -70,6 +71,7 @@ class DefaultStyles { this.underline, this.strikeThrough, this.link, + this.placeHolder, this.lists, this.quote, this.code, @@ -144,6 +146,15 @@ class DefaultStyles { color: themeData.accentColor, decoration: TextDecoration.underline, ), + placeHolder: DefaultTextBlockStyle( + defaultTextStyle.style.copyWith( + fontSize: 20.0, + height: 1.5, + color: Colors.grey.withOpacity(0.6), + ), + Tuple2(0.0, 0.0), + Tuple2(0.0, 0.0), + null), lists: DefaultTextBlockStyle( baseStyle, baseSpacing, Tuple2(0.0, 6.0), null), quote: DefaultTextBlockStyle( @@ -188,6 +199,7 @@ class DefaultStyles { underline: other.underline ?? this.underline, strikeThrough: other.strikeThrough ?? this.strikeThrough, link: other.link ?? this.link, + placeHolder: other.placeHolder ?? this.placeHolder, lists: other.lists ?? this.lists, quote: other.quote ?? this.quote, code: other.code ?? this.code, diff --git a/lib/widgets/editor.dart b/lib/widgets/editor.dart index 018ef0b2..29472aae 100644 --- a/lib/widgets/editor.dart +++ b/lib/widgets/editor.dart @@ -134,6 +134,7 @@ class QuillEditor extends StatefulWidget { final bool autoFocus; final bool showCursor; final bool readOnly; + final String placeholder; final bool enableInteractiveSelection; final double minHeight; final double maxHeight; @@ -154,6 +155,7 @@ class QuillEditor extends StatefulWidget { @required this.autoFocus, this.showCursor, @required this.readOnly, + this.placeholder, this.enableInteractiveSelection, this.minHeight, this.maxHeight, @@ -256,6 +258,7 @@ class _QuillEditorState extends State widget.scrollable, widget.padding, widget.readOnly, + widget.placeholder, widget.onLaunchUrl, ToolbarOptions( copy: true, @@ -359,6 +362,9 @@ class _QuillEditorSelectionGestureDetectorBuilder } bool _onTapping(TapUpDetails details) { + if (_state.widget.controller.document.isEmpty()) { + return false; + } TextPosition pos = getRenderEditor().getPositionForOffset(details.globalPosition); containerNode.ChildQuery result = diff --git a/lib/widgets/raw_editor.dart b/lib/widgets/raw_editor.dart index 891bff86..fbbb8a83 100644 --- a/lib/widgets/raw_editor.dart +++ b/lib/widgets/raw_editor.dart @@ -1,3 +1,5 @@ +import 'dart:convert'; + import 'package:flutter/cupertino.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/gestures.dart'; @@ -32,6 +34,7 @@ class RawEditor extends StatefulWidget { final bool scrollable; final EdgeInsetsGeometry padding; final bool readOnly; + final String placeholder; final ValueChanged onLaunchUrl; final ToolbarOptions toolbarOptions; final bool showSelectionHandles; @@ -58,6 +61,7 @@ class RawEditor extends StatefulWidget { this.scrollable, this.padding, this.readOnly, + this.placeholder, this.onLaunchUrl, this.toolbarOptions, this.showSelectionHandles, @@ -504,6 +508,12 @@ class RawEditorState extends EditorState super.build(context); Document _doc = widget.controller.document; + if (_doc.isEmpty() && + !widget.focusNode.hasFocus && + widget.placeholder != null) { + _doc = Document.fromJson(jsonDecode( + '[{"attributes":{"placeholder":true},"insert":"${widget.placeholder}\\n"}]')); + } Widget child = CompositedTransformTarget( link: _toolbarLayerLink, diff --git a/lib/widgets/text_line.dart b/lib/widgets/text_line.dart index 6d7efa6b..986cf762 100644 --- a/lib/widgets/text_line.dart +++ b/lib/widgets/text_line.dart @@ -88,6 +88,11 @@ class TextLine extends StatelessWidget { TextStyle textStyle = TextStyle(); + if (line.style.containsKey(Attribute.placeholder.key)) { + textStyle = defaultStyles.placeHolder.style; + return TextSpan(children: children, style: textStyle); + } + Attribute header = line.style.attributes[Attribute.header.key]; Map m = { Attribute.h1: defaultStyles.h1.style, From 81fbca0dc83f272e30d17124b75e532aec43ca76 Mon Sep 17 00:00:00 2001 From: li3317 Date: Sat, 20 Feb 2021 22:35:33 -0500 Subject: [PATCH 14/22] bump version to 0.2.12 --- CHANGELOG.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b3a4b172..0a6c79dc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -87,4 +87,7 @@ * Update TextInputConfiguration autocorrect to true in stable branch. ## [0.2.11] -* Fix static analysis error. \ No newline at end of file +* Fix static analysis error. + +## [0.2.12] +* Support placeholder. \ No newline at end of file From 2d81b702261fc0af01261e0671d8e7dc11c0233c Mon Sep 17 00:00:00 2001 From: li3317 Date: Sat, 20 Feb 2021 22:39:57 -0500 Subject: [PATCH 15/22] update pubspec yaml version and format code --- lib/models/documents/document.dart | 4 +++- pubspec.yaml | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/models/documents/document.dart b/lib/models/documents/document.dart index f41ee0bd..1573f9af 100644 --- a/lib/models/documents/document.dart +++ b/lib/models/documents/document.dart @@ -249,7 +249,9 @@ class Document { } Delta delta = node.toDelta(); - return delta.length == 1 && delta.first.data == '\n' && delta.first.key == 'insert'; + return delta.length == 1 && + delta.first.data == '\n' && + delta.first.key == 'insert'; } } diff --git a/pubspec.yaml b/pubspec.yaml index b601cff1..2c925516 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: flutter_quill description: One client and affiliated collaborator of Flutter Quill is Bullet Journal App. -version: 0.2.11 +version: 0.2.12 #author: bulletjournal homepage: https://bulletjournal.us/home/index.html repository: https://github.com/singerdmx/flutter-quill.git From 4f044e2b0925634199442f98930ca8f3760ec306 Mon Sep 17 00:00:00 2001 From: singerdmx Date: Sun, 21 Feb 2021 06:33:50 -0800 Subject: [PATCH 16/22] Rename uploadFileCallback to onImagePickCallback --- README.md | 4 ++-- app/lib/pages/home_page.dart | 3 ++- app/pubspec.lock | 4 ++-- example/main.dart | 2 +- lib/widgets/text_line.dart | 2 +- lib/widgets/toolbar.dart | 20 ++++++++++---------- 6 files changed, 18 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 4b03b0ac..b8f8b6be 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ and then embed the toolbar and the editor, within your app. For example: Column( children: [ QuillToolbar.basic( - controller: _controller, uploadFileCallback: _uploadImageCallBack), + controller: _controller, onImageTapCallBack: _uploadImageCallBack), Expanded( child: Container( child: QuillEditor.basic( @@ -65,7 +65,7 @@ _controller = QuillController( ## Configuration -The `QuillToolbar` class lets you customise which formating options are available. To prevent the image uploading widget from appearing, set `uploadFileCallback` to null. +The `QuillToolbar` class lets you customise which formatting options are available. To prevent the image uploading widget from appearing, set `onImageTapCallBack` to null. ## Web diff --git a/app/lib/pages/home_page.dart b/app/lib/pages/home_page.dart index dafa4859..fe8c101b 100644 --- a/app/lib/pages/home_page.dart +++ b/app/lib/pages/home_page.dart @@ -125,12 +125,13 @@ class _HomePageState extends State { Container( child: QuillToolbar.basic( controller: _controller, - uploadFileCallback: _fakeUploadImageCallBack), + onImageTapCallBack: _fakeUploadImageCallBack), ) ], ); } + /// Upload the image file to AWS s3 when image is picked Future _fakeUploadImageCallBack(File file) async { print(file); var completer = new Completer(); diff --git a/app/pubspec.lock b/app/pubspec.lock index 66f4b1e0..ec94357a 100644 --- a/app/pubspec.lock +++ b/app/pubspec.lock @@ -103,7 +103,7 @@ packages: path: ".." relative: true source: path - version: "0.2.9" + version: "0.2.12" flutter_test: dependency: "direct dev" description: flutter @@ -141,7 +141,7 @@ packages: name: image_picker url: "https://pub.dartlang.org" source: hosted - version: "0.6.7+17" + version: "0.6.7+22" image_picker_platform_interface: dependency: transitive description: diff --git a/example/main.dart b/example/main.dart index b79b35e5..c10e3a7b 100644 --- a/example/main.dart +++ b/example/main.dart @@ -20,7 +20,7 @@ class _HomePageState extends State { body: Column( children: [ QuillToolbar.basic( - controller: _controller, uploadFileCallback: _uploadImageCallBack), + controller: _controller, onImageTapCallBack: _uploadImageCallBack), Expanded( child: Container( child: QuillEditor.basic( diff --git a/lib/widgets/text_line.dart b/lib/widgets/text_line.dart index 986cf762..8608e69b 100644 --- a/lib/widgets/text_line.dart +++ b/lib/widgets/text_line.dart @@ -48,7 +48,7 @@ class TextLine extends StatelessWidget { StrutStyle.fromTextStyle(textSpan.style, forceStrutHeight: true); final textAlign = _getTextAlign(); RichText child = RichText( - text: textSpan, + text: TextSpan(children: [textSpan]), textAlign: textAlign, textDirection: textDirection, strutStyle: strutStyle, diff --git a/lib/widgets/toolbar.dart b/lib/widgets/toolbar.dart index 69de725a..a05fde04 100644 --- a/lib/widgets/toolbar.dart +++ b/lib/widgets/toolbar.dart @@ -14,7 +14,7 @@ import 'controller.dart'; double iconSize = 18.0; double kToolbarHeight = iconSize * 2; -typedef UploadFileCallback = Future Function(File file); +typedef OnImagePickCallback = Future Function(File file); class InsertEmbedButton extends StatelessWidget { final QuillController controller; @@ -490,7 +490,7 @@ class ImageButton extends StatefulWidget { final QuillController controller; - final UploadFileCallback uploadFileCallback; + final OnImagePickCallback onImagePickCallback; final ImageSource imageSource; @@ -499,7 +499,7 @@ class ImageButton extends StatefulWidget { @required this.icon, @required this.controller, @required this.imageSource, - this.uploadFileCallback}) + this.onImagePickCallback}) : assert(icon != null), assert(controller != null), super(key: key); @@ -515,10 +515,10 @@ class _ImageButtonState extends State { final PickedFile pickedFile = await _picker.getImage(source: source); final File file = File(pickedFile.path); - if (file == null || widget.uploadFileCallback == null) return null; + if (file == null || widget.onImagePickCallback == null) return null; // We simply return the absolute path to selected file. try { - String url = await widget.uploadFileCallback(file); + String url = await widget.onImagePickCallback(file); print('Image uploaded and its url is $url'); return url; } catch (error) { @@ -891,7 +891,7 @@ class QuillToolbar extends StatefulWidget implements PreferredSizeWidget { bool showLink = true, bool showHistory = true, bool showHorizontalRule = false, - UploadFileCallback uploadFileCallback}) { + OnImagePickCallback onImageTapCallBack}) { iconSize = toolbarIconSize; return QuillToolbar(key: key, children: [ Visibility( @@ -974,22 +974,22 @@ class QuillToolbar extends StatefulWidget implements PreferredSizeWidget { ), SizedBox(width: 0.6), Visibility( - visible: uploadFileCallback != null, + visible: onImageTapCallBack != null, child: ImageButton( icon: Icons.image, controller: controller, imageSource: ImageSource.gallery, - uploadFileCallback: uploadFileCallback, + onImagePickCallback: onImageTapCallBack, ), ), SizedBox(width: 0.6), Visibility( - visible: uploadFileCallback != null, + visible: onImageTapCallBack != null, child: ImageButton( icon: Icons.photo_camera, controller: controller, imageSource: ImageSource.camera, - uploadFileCallback: uploadFileCallback, + onImagePickCallback: onImageTapCallBack, ), ), Visibility( From 9bcee88705eef527a81bbffd61a6d328869e9389 Mon Sep 17 00:00:00 2001 From: singerdmx Date: Sun, 21 Feb 2021 06:39:47 -0800 Subject: [PATCH 17/22] Rename onImageTapCallBack to onImagePickCallback --- README.md | 4 ++-- app/lib/pages/home_page.dart | 2 +- example/main.dart | 2 +- lib/widgets/toolbar.dart | 10 +++++----- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index b8f8b6be..0738a0f6 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ and then embed the toolbar and the editor, within your app. For example: Column( children: [ QuillToolbar.basic( - controller: _controller, onImageTapCallBack: _uploadImageCallBack), + controller: _controller, onImagePickCallback: _uploadImageCallBack), Expanded( child: Container( child: QuillEditor.basic( @@ -65,7 +65,7 @@ _controller = QuillController( ## Configuration -The `QuillToolbar` class lets you customise which formatting options are available. To prevent the image uploading widget from appearing, set `onImageTapCallBack` to null. +The `QuillToolbar` class lets you customise which formatting options are available. To prevent the image uploading widget from appearing, set `onImagePickCallback` to null. ## Web diff --git a/app/lib/pages/home_page.dart b/app/lib/pages/home_page.dart index fe8c101b..9f8c11c2 100644 --- a/app/lib/pages/home_page.dart +++ b/app/lib/pages/home_page.dart @@ -125,7 +125,7 @@ class _HomePageState extends State { Container( child: QuillToolbar.basic( controller: _controller, - onImageTapCallBack: _fakeUploadImageCallBack), + onImagePickCallback: _fakeUploadImageCallBack), ) ], ); diff --git a/example/main.dart b/example/main.dart index c10e3a7b..e45f4298 100644 --- a/example/main.dart +++ b/example/main.dart @@ -20,7 +20,7 @@ class _HomePageState extends State { body: Column( children: [ QuillToolbar.basic( - controller: _controller, onImageTapCallBack: _uploadImageCallBack), + controller: _controller, onImagePickCallback: _uploadImageCallBack), Expanded( child: Container( child: QuillEditor.basic( diff --git a/lib/widgets/toolbar.dart b/lib/widgets/toolbar.dart index a05fde04..c7b4198c 100644 --- a/lib/widgets/toolbar.dart +++ b/lib/widgets/toolbar.dart @@ -891,7 +891,7 @@ class QuillToolbar extends StatefulWidget implements PreferredSizeWidget { bool showLink = true, bool showHistory = true, bool showHorizontalRule = false, - OnImagePickCallback onImageTapCallBack}) { + OnImagePickCallback onImagePickCallback}) { iconSize = toolbarIconSize; return QuillToolbar(key: key, children: [ Visibility( @@ -974,22 +974,22 @@ class QuillToolbar extends StatefulWidget implements PreferredSizeWidget { ), SizedBox(width: 0.6), Visibility( - visible: onImageTapCallBack != null, + visible: onImagePickCallback != null, child: ImageButton( icon: Icons.image, controller: controller, imageSource: ImageSource.gallery, - onImagePickCallback: onImageTapCallBack, + onImagePickCallback: onImagePickCallback, ), ), SizedBox(width: 0.6), Visibility( - visible: onImageTapCallBack != null, + visible: onImagePickCallback != null, child: ImageButton( icon: Icons.photo_camera, controller: controller, imageSource: ImageSource.camera, - onImagePickCallback: onImageTapCallBack, + onImagePickCallback: onImagePickCallback, ), ), Visibility( From 5dcbf78a98179583365d16c687907851a506c6f7 Mon Sep 17 00:00:00 2001 From: ArjanAswal Date: Sun, 21 Feb 2021 20:38:16 +0530 Subject: [PATCH 18/22] Change the image pick callback function --- app/lib/pages/home_page.dart | 20 ++++++++++++-------- app/pubspec.yaml | 1 + 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/app/lib/pages/home_page.dart b/app/lib/pages/home_page.dart index 9f8c11c2..4313a7e8 100644 --- a/app/lib/pages/home_page.dart +++ b/app/lib/pages/home_page.dart @@ -1,6 +1,7 @@ import 'dart:async'; import 'dart:convert'; import 'dart:io'; +import 'package:path/path.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; @@ -10,6 +11,7 @@ import 'package:flutter_quill/widgets/controller.dart'; import 'package:flutter_quill/widgets/default_styles.dart'; import 'package:flutter_quill/widgets/editor.dart'; import 'package:flutter_quill/widgets/toolbar.dart'; +import 'package:path_provider/path_provider.dart'; import 'package:tuple/tuple.dart'; import 'read_only_page.dart'; @@ -125,19 +127,21 @@ class _HomePageState extends State { Container( child: QuillToolbar.basic( controller: _controller, - onImagePickCallback: _fakeUploadImageCallBack), + onImagePickCallback: _onImagePickCallback), ) ], ); } - /// Upload the image file to AWS s3 when image is picked - Future _fakeUploadImageCallBack(File file) async { - print(file); - var completer = new Completer(); - completer.complete( - 'https://user-images.githubusercontent.com/122956/72955931-ccc07900-3d52-11ea-89b1-d468a6e2aa2b.png'); - return completer.future; + // Renders the image picked by imagePicker from local file storage + // You can also upload the picked image to any server (eg : AWS s3 or Firebase) and then return the uploaded image URL + Future _onImagePickCallback(File file) async { + if (file == null) return null; + // Copies the picked file from temporary cache to applications directory + Directory appDocDir = await getApplicationDocumentsDirectory(); + File copiedFile = + await file.copy('${appDocDir.path}/${basename(file.path)}'); + return copiedFile.path.toString(); } Widget _buildMenuBar(BuildContext context) { diff --git a/app/pubspec.yaml b/app/pubspec.yaml index 3a6814e0..4d471487 100644 --- a/app/pubspec.yaml +++ b/app/pubspec.yaml @@ -28,6 +28,7 @@ dependencies: # The following adds the Cupertino Icons font to your application. # Use with the CupertinoIcons class for iOS style icons. cupertino_icons: ^1.0.0 + path_provider: ^1.6.27 flutter_quill: path: ../ From b810dc00030fc4318a110bf41abbc6b9e2e20766 Mon Sep 17 00:00:00 2001 From: Xin Yao Date: Sun, 21 Feb 2021 07:21:21 -0800 Subject: [PATCH 19/22] Update home page --- app/lib/pages/home_page.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/lib/pages/home_page.dart b/app/lib/pages/home_page.dart index 4313a7e8..de343836 100644 --- a/app/lib/pages/home_page.dart +++ b/app/lib/pages/home_page.dart @@ -160,7 +160,7 @@ class _HomePageState extends State { void _readOnly() { Navigator.push( - context, + super.context, MaterialPageRoute( builder: (BuildContext context) => ReadOnlyPage(), ), From c561c852b021bb53b3c993085786551e2e6ce52a Mon Sep 17 00:00:00 2001 From: Xin Yao Date: Sun, 21 Feb 2021 07:32:40 -0800 Subject: [PATCH 20/22] Update README --- README.md | 8 +++++--- example/main.dart | 11 +---------- 2 files changed, 6 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 0738a0f6..76a347a9 100644 --- a/README.md +++ b/README.md @@ -25,8 +25,7 @@ and then embed the toolbar and the editor, within your app. For example: ```dart Column( children: [ - QuillToolbar.basic( - controller: _controller, onImagePickCallback: _uploadImageCallBack), + QuillToolbar.basic(controller: _controller), Expanded( child: Container( child: QuillEditor.basic( @@ -38,6 +37,7 @@ Column( ], ) ``` +Check out [Sample Page] for advanced usage. ## Input / Output @@ -65,7 +65,8 @@ _controller = QuillController( ## Configuration -The `QuillToolbar` class lets you customise which formatting options are available. To prevent the image uploading widget from appearing, set `onImagePickCallback` to null. +The `QuillToolbar` class lets you customise which formatting options are available. +[Sample Page] provided sample code for advanced usage and configuration. ## Web @@ -93,3 +94,4 @@ One client and affiliated collaborator of **[FlutterQuill]** is Bullet Journal A [FlutterQuill]: https://pub.dev/packages/flutter_quill [ReactQuill]: https://github.com/zenoamaro/react-quill [Slack Group]: https://join.slack.com/t/bulletjournal1024/shared_invite/zt-fys7t9hi-ITVU5PGDen1rNRyCjdcQ2g +[Sample Page]: https://github.com/singerdmx/flutter-quill/blob/master/app/lib/pages/home_page.dart diff --git a/example/main.dart b/example/main.dart index e45f4298..a523c5a6 100644 --- a/example/main.dart +++ b/example/main.dart @@ -1,6 +1,3 @@ -import 'dart:async'; -import 'dart:io'; - import 'package:flutter/material.dart'; import 'package:flutter_quill/widgets/controller.dart'; import 'package:flutter_quill/widgets/editor.dart'; @@ -19,8 +16,7 @@ class _HomePageState extends State { return Scaffold( body: Column( children: [ - QuillToolbar.basic( - controller: _controller, onImagePickCallback: _uploadImageCallBack), + QuillToolbar.basic(controller: _controller), Expanded( child: Container( child: QuillEditor.basic( @@ -32,9 +28,4 @@ class _HomePageState extends State { ], )); } - - Future _uploadImageCallBack(File file) async { - // call upload file API and return file's absolute url - return new Completer().future; - } } From a07d2db906e88514885068337c098795ff3aae8f Mon Sep 17 00:00:00 2001 From: Xin Yao Date: Sun, 21 Feb 2021 07:34:00 -0800 Subject: [PATCH 21/22] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 76a347a9..73c5079e 100644 --- a/README.md +++ b/README.md @@ -66,7 +66,7 @@ _controller = QuillController( ## Configuration The `QuillToolbar` class lets you customise which formatting options are available. -[Sample Page] provided sample code for advanced usage and configuration. +[Sample Page] provides sample code for advanced usage and configuration. ## Web From 6cd6abf3cd9af14fa2ac4d5b1bd6d5761e55a71a Mon Sep 17 00:00:00 2001 From: Xin Yao Date: Sun, 21 Feb 2021 12:15:55 -0800 Subject: [PATCH 22/22] Upgrade version --- CHANGELOG.md | 5 ++++- pubspec.yaml | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0a6c79dc..7480006f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -90,4 +90,7 @@ * Fix static analysis error. ## [0.2.12] -* Support placeholder. \ No newline at end of file +* Support placeholder. + +## [0.3.0] +* Line Height calculated based on font size. \ No newline at end of file diff --git a/pubspec.yaml b/pubspec.yaml index 2c925516..abedfacf 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: flutter_quill description: One client and affiliated collaborator of Flutter Quill is Bullet Journal App. -version: 0.2.12 +version: 0.3.0 #author: bulletjournal homepage: https://bulletjournal.us/home/index.html repository: https://github.com/singerdmx/flutter-quill.git