From a7329524dbb9b7c20d65cc5d7dcb9449905fe096 Mon Sep 17 00:00:00 2001 From: tanay Date: Fri, 19 Feb 2021 17:24:19 -0500 Subject: [PATCH] Add code documentation, more minor code cleanup --- README.md | 11 ++++---- example/lib/main.dart | 6 ++--- lib/html_editor.dart | 52 ++++++++++++++++++++++++++++++++----- lib/html_editor_widget.dart | 33 +++++++++++------------ lib/utils/pick_image.dart | 6 +++++ pubspec.yaml | 2 +- 6 files changed, 77 insertions(+), 33 deletions(-) diff --git a/README.md b/README.md index ecbd1b2f..d6cd5a3e 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ Add `android:requestLegacyExternalStorage="true"` as an attribute to the ` -### Usage +## Usage ```dart import 'package:html_editor/html_editor.dart'; @@ -38,26 +38,25 @@ import 'package:html_editor/html_editor.dart'; return HtmlEditor( hint: "Your text here...", //value: "text content initial, if any", - key: keyEditor, height: 400, ); } ``` When you want to get text from the editor: -``` - final txt = await HtmlEditor.getText(); +```dart +final txt = await HtmlEditor.getText(); ``` -### Available option parameters +### Parameters Parameter | Type | Default | Description ------------ | ------------- | ------------- | ------------- **value** | String | empty | initial text content for text editor **height** | double | 380 | height of text editor **decoration** | BoxDecoration | | Decoration editor -**useBottomSheet** | bool | true | if true, open a bottom sheet (OneUI style) to pick an image, otherwise use a dialog +**useBottomSheet** | bool | true | if true, open a bottom sheet (Android intent style) to pick an image, otherwise use a dialog **widthImage** | String | 100% | width of image picker **showBottomToolbar** | bool | true | show or hide bottom toolbar **hint** | String | empty | Placeholder hint text diff --git a/example/lib/main.dart b/example/lib/main.dart index 03d348a4..f8a8e882 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -12,13 +12,14 @@ class MyApp extends StatelessWidget { theme: ThemeData( primarySwatch: Colors.blue, ), - home: MyHomePage(title: 'Demo Flutter HTML Editor'), + home: MyHomePage(title: 'Flutter HTML Editor Example'), ); } } class MyHomePage extends StatefulWidget { MyHomePage({Key key, this.title}) : super(key: key); + final String title; @override @@ -55,7 +56,7 @@ class _MyHomePageState extends State { TextButton( style: TextButton.styleFrom(backgroundColor: Colors.blueGrey), onPressed: (){ - HtmlEditor.setEmpty(); + HtmlEditor.clear(); }, child: Text("Reset", style: TextStyle(color: Colors.white)), ), @@ -81,7 +82,6 @@ class _MyHomePageState extends State { ), ), ), - // This trailing comma makes auto-formatting nicer for build methods. ); } } diff --git a/lib/html_editor.dart b/lib/html_editor.dart index 1a0c0600..81fb5f04 100644 --- a/lib/html_editor.dart +++ b/lib/html_editor.dart @@ -5,35 +5,69 @@ import 'package:flutter/material.dart'; import 'package:flutter_inappwebview/flutter_inappwebview.dart'; import 'package:html_editor_enhanced/html_editor_widget.dart'; +/// Global variable used to get the [InAppWebViewController] of the Html editor InAppWebViewController controller; + +/// Global variable used to get the text from the Html editor String text = ""; class HtmlEditor extends StatelessWidget with WidgetsBindingObserver { HtmlEditor({ Key key, - this.value, + this.initialText, this.height = 380, this.decoration, this.useBottomSheet = true, - this.imageWidth = "100%", + this.imageWidth = 100, this.showBottomToolbar = true, this.hint - }) : super(key: key); + }) : assert(imageWidth > 0 && imageWidth <= 100), + super(key: key); + + /// The initial text that is be supplied to the Html editor. + final String initialText; - final String value; + /// Sets the height of the Html editor. If you decide to show the bottom toolbar, + /// this height will be inclusive of the space the toolbar takes up. + /// + /// The default value is 380. final double height; + + /// The BoxDecoration to use around the Html editor. By default, the widget + /// uses a thin, dark, rounded rectangle border around the widget. final BoxDecoration decoration; + + /// Specifies whether the widget should use a bottom sheet or a dialog to provide the image + /// picking options. The dialog is similar to an Android intent dialog. + /// + /// The default value is true. final bool useBottomSheet; - final String imageWidth; + + /// Specifies the width of an image when it is inserted into the Html editor + /// as a percentage (between 0 and 100). + /// + /// The default value is 100. + final double imageWidth; + + /// Specifies whether the bottom toolbar for picking an image or copy/pasting + /// is shown on the widget. + /// + /// The default value is true. final bool showBottomToolbar; + + /// Sets the Html editor's hint (text displayed when there is no text in the + /// editor). final String hint; + /// Gets the text from the editor and returns it as a [String]. static Future getText() async { await controller.evaluateJavascript(source: "console.log(document.getElementsByClassName('note-editable')[0].innerHTML);"); return text; } + /// Sets the text of the editor. Some pre-processing is applied to convert + /// [String] elements like "\n" to HTML elements. static void setText(String text) { String txtIsi = text .replaceAll("'", '\\"') @@ -51,19 +85,23 @@ class HtmlEditor extends StatelessWidget with WidgetsBindingObserver { controller.evaluateJavascript(source: txt); } + /// Sets the editor to full-screen mode. static void setFullScreen() { controller.evaluateJavascript(source: '\$("#summernote").summernote("fullscreen.toggle");'); } + /// Sets the focus to the editor. static void setFocus() { controller.evaluateJavascript(source: "\$('#summernote').summernote('focus');"); } - static void setEmpty() { + /// Clears the editor of any text. + static void clear() { controller.evaluateJavascript(source: "\$('#summernote').summernote('reset');"); } + /// Sets the hint for the editor. static void setHint(String text) { String hint = '\$(".note-placeholder").html("$text");'; controller.evaluateJavascript(source: hint); @@ -80,7 +118,7 @@ class HtmlEditor extends StatelessWidget with WidgetsBindingObserver { ), child: HtmlEditorWidget( key: key, - value: value, + value: initialText, height: height, useBottomSheet: useBottomSheet, imageWidth: imageWidth, diff --git a/lib/html_editor_widget.dart b/lib/html_editor_widget.dart index 50cc686d..31fabf15 100644 --- a/lib/html_editor_widget.dart +++ b/lib/html_editor_widget.dart @@ -14,19 +14,17 @@ class HtmlEditorWidget extends StatelessWidget with WidgetsBindingObserver { HtmlEditorWidget({ Key key, this.value, - this.height = 380, - this.decoration, - this.useBottomSheet = true, - this.imageWidth = "100%", - this.showBottomToolbar = true, + this.height, + this.useBottomSheet, + this.imageWidth, + this.showBottomToolbar, this.hint }) : super(key: key); final String value; final double height; - final BoxDecoration decoration; final bool useBottomSheet; - final String imageWidth; + final double imageWidth; final bool showBottomToolbar; final String hint; final UniqueKey webViewKey = UniqueKey(); @@ -56,17 +54,19 @@ class HtmlEditorWidget extends StatelessWidget with WidgetsBindingObserver { gestureRecognizers: { Factory(() => VerticalDragGestureRecognizer()) }, - onConsoleMessage: (controller, message) { - String isi = message.message; - if (isi.isEmpty || - isi == "

" || - isi == "


" || - isi == "


") { - isi = ""; + onConsoleMessage: (controller, consoleMessage) { + String message = consoleMessage.message; + //todo determine whether this processing is necessary + if (message.isEmpty || + message == "

" || + message == "


" || + message == "


") { + message = ""; } - text = isi; + text = message; }, onLoadStop: (InAppWebViewController controller, String url) { + //set the hint once the editor is loaded if (hint != null) { HtmlEditor.setHint(hint); } else { @@ -74,6 +74,7 @@ class HtmlEditorWidget extends StatelessWidget with WidgetsBindingObserver { } HtmlEditor.setFullScreen(); + //set the text once the editor is loaded if (value != null) { HtmlEditor.setText(value); } @@ -102,7 +103,7 @@ class HtmlEditorWidget extends StatelessWidget with WidgetsBindingObserver { String filename = p.basename(file.path); List imageBytes = await file.readAsBytes(); String base64Image = - ""; String txt = diff --git a/lib/utils/pick_image.dart b/lib/utils/pick_image.dart index bbe9ebda..2e9727cc 100644 --- a/lib/utils/pick_image.dart +++ b/lib/utils/pick_image.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:image_picker/image_picker.dart'; +/// Widget for the toolbar icon Widget toolbarIcon(IconData icon, String title, {Function() onTap}) { return InkWell( onTap: onTap, @@ -27,6 +28,7 @@ Widget toolbarIcon(IconData icon, String title, {Function() onTap}) { ); } +/// Function that opens a dialog to pick an image Future dialogPickImage(BuildContext context) async { PickedFile file = await showDialog( context: context, @@ -50,6 +52,7 @@ Future dialogPickImage(BuildContext context) async { return file; } +/// Function that opens a bottom sheet to pick an image Future bottomSheetPickImage(BuildContext context) async { PickedFile file = await showModalBottomSheet( shape: RoundedRectangleBorder( @@ -70,6 +73,7 @@ Future bottomSheetPickImage(BuildContext context) async { return file; } +/// Widget for the buttons to pick an image class PickImageWidget extends StatelessWidget { @override Widget build(BuildContext context) { @@ -142,6 +146,8 @@ class PickImageWidget extends StatelessWidget { ); } + /// Gets an image either from the camera or from the gallery. Once complete, + /// the [Navigator] is popped and the picked image (if any) is returned. Future getImage(bool fromCamera, BuildContext context) async { try { final picker = ImagePicker(); diff --git a/pubspec.yaml b/pubspec.yaml index aedf913c..acd450ea 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -11,7 +11,7 @@ dependencies: flutter: sdk: flutter flutter_inappwebview: ^4.0.0+4 - image_picker: ^0.6.7+22 + image_picker: ^0.7.0-nullsafety path: ^1.8.0 mime: ^0.9.6+2