diff --git a/README.md b/README.md index 0d5210d..462ed63 100644 --- a/README.md +++ b/README.md @@ -34,15 +34,17 @@ Based on https://github.com/dankito/RichTextEditor, but for Flutter. RichEditor( key: keyEditor, value: 'initial html here', - placeholder: 'Start typing', - // backgroundColor: Colors.blueGrey, // Editor's bg color - // baseTextColor: Colors.white, - // editor padding - padding: EdgeInsets.symmetric(horizontal: 5.0), - // font name - baseFontFamily: 'sans-serif', - // Position of the editing bar (BarPosition.TOP or BarPosition.BOTTOM) - barPosition: BarPosition.TOP, + editorOptions: RichEditorOptions( + placeholder: 'Start typing', + // backgroundColor: Colors.blueGrey, // Editor's bg color + // baseTextColor: Colors.white, + // editor padding + padding: EdgeInsets.symmetric(horizontal: 5.0), + // font name + baseFontFamily: 'sans-serif', + // Position of the editing bar (BarPosition.TOP or BarPosition.BOTTOM) + barPosition: BarPosition.TOP, + ), // You can return a Link (maybe you need to upload the image to your // storage before displaying in the editor or you can also use base64 getImageUrl: (image) { diff --git a/example/lib/basic.dart b/example/lib/basic.dart new file mode 100644 index 0000000..d522606 --- /dev/null +++ b/example/lib/basic.dart @@ -0,0 +1,94 @@ +import 'dart:convert'; + +import 'package:flutter/material.dart'; +import 'package:rich_editor/rich_editor.dart'; + +class BasicDemo extends StatelessWidget { + GlobalKey keyEditor = GlobalKey(); + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('Basic Demo'), + actions: [ + PopupMenuButton( + child: IconButton( + icon: Icon(Icons.more_vert), + onPressed: null, + disabledColor: Colors.white, + ), + itemBuilder: (context) { + return [ + PopupMenuItem( + child: Text('Get HTML'), + value: 0, + ), + PopupMenuItem( + child: Text('Clear content'), + value: 1, + ), + PopupMenuItem( + child: Text('Hide keyboard'), + value: 2, + ), + PopupMenuItem( + child: Text('Show Keyboard'), + value: 3, + ), + ]; + }, + onSelected: (val) async { + switch (val) { + case 0: + String? html = await keyEditor.currentState?.getHtml(); + print(html); + break; + case 1: + await keyEditor.currentState?.clear(); + break; + case 2: + await keyEditor.currentState?.unFocus(); + break; + case 3: + await keyEditor.currentState?.focus(); + break; + } + }, + ), + ], + ), + body: RichEditor( + key: keyEditor, +// value: ''' +//

Heading 1

+//

Heading 2

+//

Heading 3

+//

Heading 4

+//
Heading 5
+//
Heading 6
+// ''', // initial HTML data + editorOptions: RichEditorOptions( + placeholder: 'Start typing', + // backgroundColor: Colors.blueGrey, // Editor's bg color + // baseTextColor: Colors.white, + // editor padding + padding: EdgeInsets.symmetric(horizontal: 5.0), + // font name + baseFontFamily: 'sans-serif', + // Position of the editing bar (BarPosition.TOP or BarPosition.BOTTOM) + barPosition: BarPosition.TOP, + ), + + // You can return a Link (maybe you need to upload the image to your + // storage before displaying in the editor or you can also use base64 + getImageUrl: (image) { + String link = 'https://avatars.githubusercontent.com/u/24323581?v=4'; + String base64 = base64Encode(image.readAsBytesSync()); + String base64String = 'data:image/png;base64, $base64'; + return base64String; + }, + ), + ); + } +} diff --git a/example/lib/custom_toolbar_demo.dart b/example/lib/custom_toolbar_demo.dart new file mode 100644 index 0000000..2a6458f --- /dev/null +++ b/example/lib/custom_toolbar_demo.dart @@ -0,0 +1,91 @@ +import 'dart:convert'; + +import 'package:flutter/material.dart'; +import 'package:rich_editor/rich_editor.dart'; + +class CustomToolbarDemo extends StatefulWidget { + @override + _CustomToolbarDemoState createState() => _CustomToolbarDemoState(); +} + +class _CustomToolbarDemoState extends State { + GlobalKey keyEditor = GlobalKey(); + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('Custom Toolbar Demo'), + actions: [ + PopupMenuButton( + child: IconButton( + icon: Icon(Icons.more_vert), + onPressed: null, + disabledColor: Colors.white, + ), + itemBuilder: (context) { + return [ + PopupMenuItem( + child: Text('Get HTML'), + value: 0, + ), + PopupMenuItem( + child: Text('Clear content'), + value: 1, + ), + PopupMenuItem( + child: Text('Hide keyboard'), + value: 2, + ), + PopupMenuItem( + child: Text('Show Keyboard'), + value: 3, + ), + ]; + }, + onSelected: (val) async { + switch (val) { + case 0: + String? html = await keyEditor.currentState?.getHtml(); + print(html); + break; + case 1: + await keyEditor.currentState?.clear(); + break; + case 2: + await keyEditor.currentState?.unFocus(); + break; + case 3: + await keyEditor.currentState?.focus(); + break; + } + }, + ), + ], + ), + body: RichEditor( + key: keyEditor, +// value: '', // initial HTML data + editorOptions: RichEditorOptions( + placeholder: 'Start typing', + // backgroundColor: Colors.blueGrey, // Editor's bg color + // baseTextColor: Colors.white, + // editor padding + padding: EdgeInsets.symmetric(horizontal: 5.0), + // font name + baseFontFamily: 'sans-serif', + // Position of the editing bar (BarPosition.TOP or BarPosition.BOTTOM) + barPosition: BarPosition.TOP, + ), + + // You can return a Link (maybe you need to upload the image to your + // storage before displaying in the editor or you can also use base64 + getImageUrl: (image) { + String link = 'https://avatars.githubusercontent.com/u/24323581?v=4'; + String base64 = base64Encode(image.readAsBytesSync()); + String base64String = 'data:image/png;base64, $base64'; + return base64String; + }, + ), + ); + } +} diff --git a/example/lib/main.dart b/example/lib/main.dart index 532275e..7c6d0ef 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -1,5 +1,6 @@ import 'dart:convert'; +import 'package:example/basic.dart'; import 'package:flutter/material.dart'; import 'package:rich_editor/rich_editor.dart'; @@ -16,102 +17,7 @@ class MyApp extends StatelessWidget { theme: ThemeData( primarySwatch: Colors.blue, ), - home: MyHomePage(title: 'Rich Editor Demo'), - ); - } -} - -class MyHomePage extends StatefulWidget { - MyHomePage({Key? key, required this.title}) : super(key: key); - final String title; - - @override - _MyHomePageState createState() => _MyHomePageState(); -} - -class _MyHomePageState extends State { - GlobalKey keyEditor = GlobalKey(); - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - title: Text(widget.title), - actions: [ - PopupMenuButton( - child: IconButton( - icon: Icon(Icons.more_vert), - onPressed: null, - disabledColor: Colors.white, - ), - itemBuilder: (context) { - return [ - PopupMenuItem( - child: Text('Get HTML'), - value: 0, - ), - PopupMenuItem( - child: Text('Clear content'), - value: 1, - ), - PopupMenuItem( - child: Text('Hide keyboard'), - value: 2, - ), - PopupMenuItem( - child: Text('Show Keyboard'), - value: 3, - ), - ]; - }, - onSelected: (val) async { - switch (val) { - case 0: - String? html = await keyEditor.currentState?.getHtml(); - print(html); - break; - case 1: - await keyEditor.currentState?.clear(); - break; - case 2: - await keyEditor.currentState?.unFocus(); - break; - case 3: - await keyEditor.currentState?.focus(); - break; - } - }, - ), - ], - ), - body: RichEditor( - key: keyEditor, -// value: ''' -//

Heading 1

-//

Heading 2

-//

Heading 3

-//

Heading 4

-//
Heading 5
-//
Heading 6
-// ''', // initial HTML data - placeholder: 'Start typing', - // backgroundColor: Colors.blueGrey, // Editor's bg color - // baseTextColor: Colors.white, - // editor padding - padding: EdgeInsets.symmetric(horizontal: 5.0), - // font name - baseFontFamily: 'sans-serif', - // Position of the editing bar (BarPosition.TOP or BarPosition.BOTTOM) - barPosition: BarPosition.TOP, - // You can return a Link (maybe you need to upload the image to your - // storage before displaying in the editor or you can also use base64 - getImageUrl: (image) { - String link = 'https://avatars.githubusercontent.com/u/24323581?v=4'; - String base64 = base64Encode(image.readAsBytesSync()); - String base64String = 'data:image/png;base64, $base64'; - return base64String; - }, - ), + home: BasicDemo(), ); } } diff --git a/lib/rich_editor.dart b/lib/rich_editor.dart index 746c738..e31a4db 100644 --- a/lib/rich_editor.dart +++ b/lib/rich_editor.dart @@ -1,6 +1,9 @@ library rich_editor; +export 'src/models/enum/bar_position.dart'; +export 'src/models/rich_editor_options.dart'; export 'src/rendering/rich_editor.dart'; +export 'src/utils/javascript_executor_base.dart'; export 'src/widgets/editor_tool_bar.dart'; export 'src/widgets/tab_button.dart'; -export 'src/models/enum.dart'; +export 'src/widgets/tab_button.dart'; diff --git a/lib/src/models/editor_state.dart b/lib/src/models/editor_state.dart index 70dde80..aa137b2 100644 --- a/lib/src/models/editor_state.dart +++ b/lib/src/models/editor_state.dart @@ -1,6 +1,5 @@ -import 'package:rich_editor/src/models/enum.dart'; - import 'command_state.dart'; +import 'enum/command_name.dart'; class EditorState { bool? didHtmlChange; diff --git a/lib/src/models/enum/bar_position.dart b/lib/src/models/enum/bar_position.dart new file mode 100644 index 0000000..d91324d --- /dev/null +++ b/lib/src/models/enum/bar_position.dart @@ -0,0 +1 @@ +enum BarPosition { TOP, BOTTOM, CUSTOM } \ No newline at end of file diff --git a/lib/src/models/enum.dart b/lib/src/models/enum/command_name.dart similarity index 95% rename from lib/src/models/enum.dart rename to lib/src/models/enum/command_name.dart index 3c3a70a..2dbb90c 100644 --- a/lib/src/models/enum.dart +++ b/lib/src/models/enum/command_name.dart @@ -38,6 +38,4 @@ enum CommandName { INSERTCHECKBOX, // pseudo commands for toggling grouped command views EXPANDING_SEARCH_VIEWING, -} - -enum BarPosition { TOP, BOTTOM } +} \ No newline at end of file diff --git a/lib/src/models/rich_editor_options.dart b/lib/src/models/rich_editor_options.dart new file mode 100644 index 0000000..0e52364 --- /dev/null +++ b/lib/src/models/rich_editor_options.dart @@ -0,0 +1,28 @@ +import 'package:flutter/material.dart'; + +import 'enum/bar_position.dart'; + +class RichEditorOptions { + Color? backgroundColor; + Color? baseTextColor; + EdgeInsets? padding; + String? placeholder; + String? baseFontFamily; + BarPosition? barPosition; + + RichEditorOptions({ + Color? backgroundColor, + Color? baseTextColor, + EdgeInsets? padding, + String? placeholder, + String? baseFontFamily, + BarPosition? barPosition, + }) { + this.backgroundColor = backgroundColor; + this.baseTextColor = baseTextColor; + this.padding = padding; + this.placeholder = placeholder; + this.baseFontFamily = baseFontFamily; + this.barPosition = barPosition; + } +} diff --git a/lib/src/rendering/rich_editor.dart b/lib/src/rendering/rich_editor.dart index 8749da9..d6c19c5 100644 --- a/lib/src/rendering/rich_editor.dart +++ b/lib/src/rendering/rich_editor.dart @@ -4,7 +4,8 @@ import 'dart:io'; import 'package:flutter/foundation.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; -import 'package:rich_editor/src/models/enum.dart'; +import 'package:rich_editor/src/models/enum/bar_position.dart'; +import 'package:rich_editor/src/models/rich_editor_options.dart'; import 'package:rich_editor/src/services/local_server.dart'; import 'package:rich_editor/src/utils/javascript_executor_base.dart'; import 'package:rich_editor/src/widgets/editor_tool_bar.dart'; @@ -12,24 +13,14 @@ import 'package:webview_flutter/webview_flutter.dart'; class RichEditor extends StatefulWidget { final String? value; - final Color? backgroundColor; - final Color? baseTextColor; - final EdgeInsets? padding; - final String? placeholder; - final String? baseFontFamily; - final BarPosition barPosition; + final RichEditorOptions? editorOptions; final Function(File image)? getImageUrl; final Function(File video)? getVideoUrl; RichEditor({ Key? key, this.value, - this.backgroundColor, - this.baseTextColor, - this.padding, - this.placeholder, - this.baseFontFamily, - this.barPosition = BarPosition.TOP, + this.editorOptions, this.getImageUrl, this.getVideoUrl, }) : super(key: key); @@ -93,7 +84,7 @@ class RichEditorState extends State { return Column( children: [ Visibility( - visible: widget.barPosition == BarPosition.TOP, + visible: widget.editorOptions!.barPosition == BarPosition.TOP, child: EditorToolBar( controller: _controller, getImageUrl: widget.getImageUrl, @@ -128,7 +119,7 @@ class RichEditorState extends State { ), ), Visibility( - visible: widget.barPosition == BarPosition.BOTTOM, + visible: widget.editorOptions!.barPosition == BarPosition.BOTTOM, child: EditorToolBar( controller: _controller, getImageUrl: widget.getImageUrl, @@ -141,16 +132,20 @@ class RichEditorState extends State { _setInitialValues() async { if (widget.value != null) await javascriptExecutor.setHtml(widget.value!); - if (widget.padding != null) - await javascriptExecutor.setPadding(widget.padding!); - if (widget.backgroundColor != null) - await javascriptExecutor.setBackgroundColor(widget.backgroundColor!); - if (widget.baseTextColor != null) - await javascriptExecutor.setBaseTextColor(widget.baseTextColor!); - if (widget.placeholder != null) - await javascriptExecutor.setPlaceholder(widget.placeholder!); - if (widget.baseFontFamily != null) - await javascriptExecutor.setBaseFontFamily(widget.baseFontFamily!); + if (widget.editorOptions!.padding != null) + await javascriptExecutor.setPadding(widget.editorOptions!.padding!); + if (widget.editorOptions!.backgroundColor != null) + await javascriptExecutor + .setBackgroundColor(widget.editorOptions!.backgroundColor!); + if (widget.editorOptions!.baseTextColor != null) + await javascriptExecutor + .setBaseTextColor(widget.editorOptions!.baseTextColor!); + if (widget.editorOptions!.placeholder != null) + await javascriptExecutor + .setPlaceholder(widget.editorOptions!.placeholder!); + if (widget.editorOptions!.baseFontFamily != null) + await javascriptExecutor + .setBaseFontFamily(widget.editorOptions!.baseFontFamily!); } /// Get current HTML from editor diff --git a/lib/src/utils/javascript_executor_base.dart b/lib/src/utils/javascript_executor_base.dart index 0ffc88d..e7962fa 100644 --- a/lib/src/utils/javascript_executor_base.dart +++ b/lib/src/utils/javascript_executor_base.dart @@ -3,7 +3,7 @@ import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:rich_editor/src/extensions/extensions.dart'; import 'package:rich_editor/src/models/editor_state.dart'; -import 'package:rich_editor/src/models/enum.dart'; +import 'package:rich_editor/src/models/enum/command_name.dart'; import 'package:webview_flutter/webview_flutter.dart'; import '../models/command_state.dart'; diff --git a/lib/src/widgets/tab_button.dart b/lib/src/widgets/tab_button.dart index e2bfafd..5658cd8 100644 --- a/lib/src/widgets/tab_button.dart +++ b/lib/src/widgets/tab_button.dart @@ -4,8 +4,9 @@ class TabButton extends StatelessWidget { final IconData? icon; final Function? onTap; final String tooltip; + final bool selected; - TabButton({this.icon, this.onTap, this.tooltip = ''}); + TabButton({this.icon, this.onTap, this.tooltip = '', this.selected = false}); @override Widget build(BuildContext context) { @@ -17,7 +18,9 @@ class TabButton extends StatelessWidget { height: 40.0, width: 40.0, decoration: BoxDecoration( - // color: Color(0xff212121), + color: selected + ? Theme.of(context).accentColor.withOpacity(0.2) + : Colors.transparent, borderRadius: BorderRadius.all( Radius.circular(5.0), ), @@ -32,7 +35,9 @@ class TabButton extends StatelessWidget { padding: const EdgeInsets.all(5.0), child: Icon( icon, - // color: Theme.of(context).accentColor, + color: selected + ? Theme.of(context).accentColor + : Theme.of(context).iconTheme.color, ), ), ),