diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index ace990a..c1bfcab 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -1,20 +1,26 @@ PODS: - Flutter (1.0.0) + - image_picker (0.0.1): + - Flutter - webview_flutter (0.0.1): - Flutter DEPENDENCIES: - Flutter (from `Flutter`) + - image_picker (from `.symlinks/plugins/image_picker/ios`) - webview_flutter (from `.symlinks/plugins/webview_flutter/ios`) EXTERNAL SOURCES: Flutter: :path: Flutter + image_picker: + :path: ".symlinks/plugins/image_picker/ios" webview_flutter: :path: ".symlinks/plugins/webview_flutter/ios" SPEC CHECKSUMS: Flutter: 434fef37c0980e73bb6479ef766c45957d4b510c + image_picker: 50e7c7ff960e5f58faa4d1f4af84a771c671bc4a webview_flutter: 9f491a9b5a66f2573946a389b2677987b0ff8c0b PODFILE CHECKSUM: aafe91acc616949ddb318b77800a7f51bffa2a4c diff --git a/example/ios/Runner/Info.plist b/example/ios/Runner/Info.plist index e3336b8..dbb2e06 100644 --- a/example/ios/Runner/Info.plist +++ b/example/ios/Runner/Info.plist @@ -41,10 +41,13 @@ UIViewControllerBasedStatusBarAppearance + NSPhotoLibraryUsageDescription + Used to demonstrate image picker plugin NSAppTransportSecurity NSAllowsArbitraryLoads + diff --git a/example/pubspec.lock b/example/pubspec.lock index 11b5882..945c298 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -62,11 +62,65 @@ packages: description: flutter source: sdk version: "0.0.0" + flutter_plugin_android_lifecycle: + dependency: transitive + description: + name: flutter_plugin_android_lifecycle + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.2" flutter_test: dependency: "direct dev" description: flutter source: sdk version: "0.0.0" + flutter_web_plugins: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" + http: + dependency: transitive + description: + name: http + url: "https://pub.dartlang.org" + source: hosted + version: "0.13.3" + http_parser: + dependency: transitive + description: + name: http_parser + url: "https://pub.dartlang.org" + source: hosted + version: "4.0.0" + image_picker: + dependency: transitive + description: + name: image_picker + url: "https://pub.dartlang.org" + source: hosted + version: "0.7.5+3" + image_picker_for_web: + dependency: transitive + description: + name: image_picker_for_web + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.0" + image_picker_platform_interface: + dependency: transitive + description: + name: image_picker_platform_interface + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.0" + js: + dependency: transitive + description: + name: js + url: "https://pub.dartlang.org" + source: hosted + version: "0.6.3" matcher: dependency: transitive description: @@ -95,6 +149,20 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.8.0" + pedantic: + dependency: transitive + description: + name: pedantic + url: "https://pub.dartlang.org" + source: hosted + version: "1.11.0" + plugin_platform_interface: + dependency: transitive + description: + name: plugin_platform_interface + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.0" rich_editor: dependency: "direct main" description: diff --git a/lib/src/widgets/custom_dialog_template.dart b/lib/src/widgets/custom_dialog_template.dart new file mode 100644 index 0000000..3b58c98 --- /dev/null +++ b/lib/src/widgets/custom_dialog_template.dart @@ -0,0 +1,31 @@ +import 'package:flutter/material.dart'; + +class CustomDialogTemplate extends StatelessWidget { + final List? body; + final Function? onDone; + final Function? onCancel; + + + CustomDialogTemplate({this.body, this.onDone, this.onCancel}); + + @override + Widget build(BuildContext context) { + return AlertDialog( + content: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: body!, + ), + actions: [ + TextButton( + onPressed: () => onDone!(), + child: Text('Done'), + ), + TextButton( + onPressed: () => onCancel!(), + child: Text('Cancel'), + ), + ], + ); + } +} diff --git a/lib/src/widgets/insert_image_dialog.dart b/lib/src/widgets/insert_image_dialog.dart new file mode 100644 index 0000000..5e47716 --- /dev/null +++ b/lib/src/widgets/insert_image_dialog.dart @@ -0,0 +1,62 @@ +import 'package:flutter/material.dart'; +import 'package:image_picker/image_picker.dart'; + +import 'custom_dialog_template.dart'; + +class InsertImageDialog extends StatefulWidget { + @override + _InsertImageDialogState createState() => _InsertImageDialogState(); +} + +class _InsertImageDialogState extends State { + TextEditingController link = TextEditingController(); + + TextEditingController alt = TextEditingController(); + + @override + Widget build(BuildContext context) { + return CustomDialogTemplate( + body: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text('Image link'), + ElevatedButton( + onPressed: () => getImage(), + child: Text('...'), + ), + ], + ), + TextField( + controller: link, + decoration: InputDecoration( + hintText: '', + ), + ), + SizedBox(height: 20.0), + Text('Alt text (optional)'), + TextField( + controller: alt, + decoration: InputDecoration( + hintText: '', + ), + ), + ], + onDone: () => Navigator.pop(context, [link.text, alt.text]), + onCancel: () => Navigator.pop(context), + ); + } + + Future getImage() async { + final picker = ImagePicker(); + var image = await picker.getImage( + source: ImageSource.gallery, + maxWidth: 800.0, + maxHeight: 600.0, + ); + + if (image != null) { + link.text = image.path; + } + } +} diff --git a/lib/src/widgets/insert_link_dialog.dart b/lib/src/widgets/insert_link_dialog.dart index 05ce47e..24d30c0 100644 --- a/lib/src/widgets/insert_link_dialog.dart +++ b/lib/src/widgets/insert_link_dialog.dart @@ -1,43 +1,33 @@ import 'package:flutter/material.dart'; +import 'custom_dialog_template.dart'; + class InsertLinkDialog extends StatelessWidget { TextEditingController link = TextEditingController(); TextEditingController label = TextEditingController(); + @override Widget build(BuildContext context) { - return AlertDialog( - title: Text('Insert Link'), - content: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisSize: MainAxisSize.min, - children: [ - Text('Link'), - TextField( - controller: link, - decoration: InputDecoration( - hintText: 'type link here', - ), + return CustomDialogTemplate( + body: [ + Text('Link'), + TextField( + controller: link, + decoration: InputDecoration( + hintText: 'type link here', ), - SizedBox(height: 20.0), - Text('Label'), - TextField( - controller: label, - decoration: InputDecoration( - hintText: 'type label text here', - ), - ), - ], - ), - actions: [ - TextButton( - onPressed: () => Navigator.pop(context, [link.text, label.text]), - child: Text('Done'), ), - TextButton( - onPressed: () => Navigator.pop(context), - child: Text('Cancel'), + SizedBox(height: 20.0), + Text('Label'), + TextField( + controller: label, + decoration: InputDecoration( + hintText: 'type label text here', + ), ), ], + onDone: () => Navigator.pop(context, [link.text, label.text]), + onCancel: () => Navigator.pop(context), ); } } diff --git a/lib/src/widgets/tabs.dart b/lib/src/widgets/tabs.dart index 0f9c1b7..80200ef 100644 --- a/lib/src/widgets/tabs.dart +++ b/lib/src/widgets/tabs.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:rich_editor/src/utils/javascript_executor_base.dart'; +import 'package:rich_editor/src/widgets/insert_image_dialog.dart'; import 'package:rich_editor/src/widgets/insert_link_dialog.dart'; import 'package:rich_editor/src/widgets/tab_button.dart'; import 'package:webview_flutter/webview_flutter.dart'; @@ -49,16 +50,75 @@ class GroupedTab extends StatelessWidget { return InsertLinkDialog(); }, ); - if(link != null) + if (link != null) await javascriptExecutorBase.insertLink(link[0], link[1]); }, ), TabButton( icon: Icons.image, onTap: () async { - await javascriptExecutorBase.insertImage( - 'https://avatars.githubusercontent.com/u/24323581?v=4' + var link = await showDialog( + context: context, + barrierDismissible: false, + builder: (_) { + return InsertImageDialog(); + }, ); + if (link != null) { + await javascriptExecutorBase.insertImage( + link[0], + alt: link[1], + ); + } + }, + ), + TabButton( + icon: Icons.format_underline, + onTap: () async { + await javascriptExecutorBase.setUnderline(); + }, + ), + TabButton( + icon: Icons.format_strikethrough, + onTap: () async { + await javascriptExecutorBase.setStrikeThrough(); + }, + ), + TabButton( + icon: Icons.superscript, + onTap: () async { + await javascriptExecutorBase.setSuperscript(); + }, + ), + TabButton( + icon: Icons.subscript, + onTap: () async { + await javascriptExecutorBase.setSubscript(); + }, + ), + TabButton( + icon: Icons.format_clear, + onTap: () async { + await javascriptExecutorBase.removeFormat(); + }, + ), + TabButton( + icon: Icons.redo, + onTap: () async { + await javascriptExecutorBase.redo(); + }, + ), + TabButton( + icon: Icons.undo, + onTap: () async { + await javascriptExecutorBase.undo(); + }, + ), + + TabButton( + icon: Icons.format_quote, + onTap: () async { + await javascriptExecutorBase.setBlockQuote(); }, ), ], diff --git a/pubspec.lock b/pubspec.lock index bc54432..5820fa2 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -55,11 +55,65 @@ packages: description: flutter source: sdk version: "0.0.0" + flutter_plugin_android_lifecycle: + dependency: transitive + description: + name: flutter_plugin_android_lifecycle + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.2" flutter_test: dependency: "direct dev" description: flutter source: sdk version: "0.0.0" + flutter_web_plugins: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" + http: + dependency: transitive + description: + name: http + url: "https://pub.dartlang.org" + source: hosted + version: "0.13.3" + http_parser: + dependency: transitive + description: + name: http_parser + url: "https://pub.dartlang.org" + source: hosted + version: "4.0.0" + image_picker: + dependency: "direct main" + description: + name: image_picker + url: "https://pub.dartlang.org" + source: hosted + version: "0.7.5+3" + image_picker_for_web: + dependency: transitive + description: + name: image_picker_for_web + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.0" + image_picker_platform_interface: + dependency: transitive + description: + name: image_picker_platform_interface + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.0" + js: + dependency: transitive + description: + name: js + url: "https://pub.dartlang.org" + source: hosted + version: "0.6.3" matcher: dependency: transitive description: @@ -88,6 +142,20 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.8.0" + pedantic: + dependency: transitive + description: + name: pedantic + url: "https://pub.dartlang.org" + source: hosted + version: "1.11.0" + plugin_platform_interface: + dependency: transitive + description: + name: plugin_platform_interface + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.0" sky_engine: dependency: transitive description: flutter diff --git a/pubspec.yaml b/pubspec.yaml index 5ca5343..a9db23a 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -11,8 +11,9 @@ dependencies: flutter: sdk: flutter webview_flutter: ^2.0.4 -# flutter_inappwebview: ^5.3.2 mime: ^1.0.0 + image_picker: ^0.7.5+3 +# path_provider: ^2.0.2 dev_dependencies: flutter_test: