From a9ae717278ab83435c9d6a6a3383fd592689cd95 Mon Sep 17 00:00:00 2001 From: Sergey Che Date: Wed, 4 Aug 2021 07:09:43 +0000 Subject: [PATCH] Always provide an option to add media from link --- example/lib/pages/home_page.dart | 35 +++++++++++-- lib/flutter_quill.dart | 1 - lib/src/utils/media_pick_setting.dart | 4 ++ lib/src/utils/media_source.dart | 5 -- lib/src/widgets/toolbar.dart | 26 +++++----- lib/src/widgets/toolbar/image_button.dart | 50 ++++++------------- .../widgets/toolbar/image_video_utils.dart | 12 +++-- lib/src/widgets/toolbar/video_button.dart | 50 ++++++------------- 8 files changed, 88 insertions(+), 95 deletions(-) create mode 100644 lib/src/utils/media_pick_setting.dart delete mode 100644 lib/src/utils/media_source.dart diff --git a/example/lib/pages/home_page.dart b/example/lib/pages/home_page.dart index ea163a42..61bd5f5b 100644 --- a/example/lib/pages/home_page.dart +++ b/example/lib/pages/home_page.dart @@ -141,9 +141,15 @@ class _HomePageState extends State { embedBuilder: defaultEmbedBuilderWeb); } var toolbar = QuillToolbar.basic( - controller: _controller!, - onImagePickCallback: _onImagePickCallback, - onVideoPickCallback: _onVideoPickCallback); + controller: _controller!, + // provide a callback to enable picking images from device. + // if omit, "image" button only allows adding images from url. + // same goes for videos. + onImagePickCallback: _onImagePickCallback, + onVideoPickCallback: _onVideoPickCallback, + // uncomment to provide a custom "pick from" dialog. + // mediaPickSettingSelector: _selectMediaPickSetting, + ); if (kIsWeb) { toolbar = QuillToolbar.basic( controller: _controller!, @@ -228,6 +234,29 @@ class _HomePageState extends State { return copiedFile.path.toString(); } + Future _selectMediaPickSetting(BuildContext context) => + showDialog( + context: context, + builder: (ctx) => AlertDialog( + contentPadding: EdgeInsets.zero, + content: Column( + mainAxisSize: MainAxisSize.min, + children: [ + TextButton.icon( + icon: const Icon(Icons.collections), + label: const Text('Gallery'), + onPressed: () => Navigator.pop(ctx, MediaPickSetting.Gallery), + ), + TextButton.icon( + icon: const Icon(Icons.link), + label: const Text('Link'), + onPressed: () => Navigator.pop(ctx, MediaPickSetting.Link), + ) + ], + ), + ), + ); + Widget _buildMenuBar(BuildContext context) { final size = MediaQuery.of(context).size; const itemStyle = TextStyle( diff --git a/lib/flutter_quill.dart b/lib/flutter_quill.dart index a3bfdaa5..6b6754ce 100644 --- a/lib/flutter_quill.dart +++ b/lib/flutter_quill.dart @@ -5,7 +5,6 @@ export 'src/models/documents/document.dart'; export 'src/models/documents/nodes/embed.dart'; export 'src/models/documents/nodes/leaf.dart'; export 'src/models/quill_delta.dart'; -export 'src/utils/media_source.dart'; export 'src/widgets/controller.dart'; export 'src/widgets/default_styles.dart'; export 'src/widgets/editor.dart'; diff --git a/lib/src/utils/media_pick_setting.dart b/lib/src/utils/media_pick_setting.dart new file mode 100644 index 00000000..06b9e8b2 --- /dev/null +++ b/lib/src/utils/media_pick_setting.dart @@ -0,0 +1,4 @@ +enum MediaPickSetting { + Gallery, + Link, +} diff --git a/lib/src/utils/media_source.dart b/lib/src/utils/media_source.dart deleted file mode 100644 index f383dece..00000000 --- a/lib/src/utils/media_source.dart +++ /dev/null @@ -1,5 +0,0 @@ -enum MediaSource { - Gallery, - Link, - GalleryAndLink, -} diff --git a/lib/src/widgets/toolbar.dart b/lib/src/widgets/toolbar.dart index 8b08ed56..dff2013c 100644 --- a/lib/src/widgets/toolbar.dart +++ b/lib/src/widgets/toolbar.dart @@ -3,7 +3,7 @@ import 'dart:io'; import 'package:flutter/material.dart'; import '../models/documents/attribute.dart'; -import '../utils/media_source.dart'; +import '../utils/media_pick_setting.dart'; import 'controller.dart'; import 'toolbar/arrow_indicated_button_list.dart'; import 'toolbar/camera_button.dart'; @@ -19,6 +19,7 @@ import 'toolbar/toggle_check_list_button.dart'; import 'toolbar/toggle_style_button.dart'; import 'toolbar/video_button.dart'; +export '../utils/media_pick_setting.dart'; export 'toolbar/clear_format_button.dart'; export 'toolbar/color_button.dart'; export 'toolbar/history_button.dart'; @@ -31,6 +32,7 @@ export 'toolbar/quill_icon_button.dart'; export 'toolbar/select_header_style_button.dart'; export 'toolbar/toggle_check_list_button.dart'; export 'toolbar/toggle_style_button.dart'; +export 'toolbar/video_button.dart'; typedef OnImagePickCallback = Future Function(File file); typedef OnVideoPickCallback = Future Function(File file); @@ -39,7 +41,7 @@ typedef WebImagePickImpl = Future Function( OnImagePickCallback onImagePickCallback); typedef WebVideoPickImpl = Future Function( OnVideoPickCallback onImagePickCallback); -typedef MediaSourceSelectorBuilder = Future Function( +typedef MediaPickSettingSelector = Future Function( BuildContext context); // The default size of the icon of a button. @@ -79,12 +81,12 @@ class QuillToolbar extends StatelessWidget implements PreferredSizeWidget { bool showHistory = true, bool showHorizontalRule = false, bool multiRowsDisplay = true, - bool showCamera = true, - MediaSource? imageSource, + bool showImageButton = true, + bool showVideoButton = true, + bool showCameraButton = true, OnImagePickCallback? onImagePickCallback, - MediaSource? videoSource, OnVideoPickCallback? onVideoPickCallback, - MediaSourceSelectorBuilder? mediaSourceSelectorBuilder, + MediaPickSettingSelector? mediaPickSettingSelector, FilePickImpl? filePickImpl, WebImagePickImpl? webImagePickImpl, WebVideoPickImpl? webVideoPickImpl, @@ -174,30 +176,28 @@ class QuillToolbar extends StatelessWidget implements PreferredSizeWidget { iconSize: toolbarIconSize, controller: controller, ), - if (imageSource != null) + if (showImageButton) ImageButton( icon: Icons.image, iconSize: toolbarIconSize, controller: controller, - source: imageSource, onImagePickCallback: onImagePickCallback, filePickImpl: filePickImpl, webImagePickImpl: webImagePickImpl, - mediaSourceSelectorBuilder: mediaSourceSelectorBuilder, + mediaPickSettingSelector: mediaPickSettingSelector, ), - if (videoSource != null) + if (showVideoButton) VideoButton( icon: Icons.movie_creation, iconSize: toolbarIconSize, controller: controller, - source: videoSource, onVideoPickCallback: onVideoPickCallback, filePickImpl: filePickImpl, webVideoPickImpl: webImagePickImpl, - mediaSourceSelectorBuilder: mediaSourceSelectorBuilder, + mediaPickSettingSelector: mediaPickSettingSelector, ), if ((onImagePickCallback != null || onVideoPickCallback != null) && - showCamera) + showCameraButton) CameraButton( icon: Icons.photo_camera, iconSize: toolbarIconSize, diff --git a/lib/src/widgets/toolbar/image_button.dart b/lib/src/widgets/toolbar/image_button.dart index 04403fd0..d30078f0 100644 --- a/lib/src/widgets/toolbar/image_button.dart +++ b/lib/src/widgets/toolbar/image_button.dart @@ -2,7 +2,7 @@ import 'package:flutter/material.dart'; import 'package:image_picker/image_picker.dart'; import '../../models/documents/nodes/embed.dart'; -import '../../utils/media_source.dart'; +import '../../utils/media_pick_setting.dart'; import '../controller.dart'; import '../link_dialog.dart'; import '../toolbar.dart'; @@ -13,19 +13,14 @@ class ImageButton extends StatelessWidget { const ImageButton({ required this.icon, required this.controller, - required this.source, this.iconSize = kDefaultIconSize, this.onImagePickCallback, this.fillColor, this.filePickImpl, this.webImagePickImpl, - this.mediaSourceSelectorBuilder, + this.mediaPickSettingSelector, Key? key, - }) : assert( - source == MediaSource.Link || onImagePickCallback != null, - 'Gallery source requires non-null onImagePickCallback', - ), - super(key: key); + }) : super(key: key); final IconData icon; final double iconSize; @@ -40,9 +35,7 @@ class ImageButton extends StatelessWidget { final FilePickImpl? filePickImpl; - final MediaSource source; - - final MediaSourceSelectorBuilder? mediaSourceSelectorBuilder; + final MediaPickSettingSelector? mediaPickSettingSelector; @override Widget build(BuildContext context) { @@ -59,30 +52,19 @@ class ImageButton extends StatelessWidget { } Future _onPressedHandler(BuildContext context) async { - switch (source) { - case MediaSource.Gallery: - _pickImage(context); - break; - case MediaSource.Link: - _typeLink(context); - break; - case MediaSource.GalleryAndLink: - final builder = - mediaSourceSelectorBuilder ?? ImageVideoUtils.selectMediaSource; - final source = await builder(context); - if (source != null) { - assert( - source != MediaSource.GalleryAndLink, - 'Source selector should return either MediaSource.Gallery or Link', - ); - - if (source == MediaSource.Gallery) { - _pickImage(context); - } else { - _typeLink(context); - } + if (onImagePickCallback != null) { + final selector = + mediaPickSettingSelector ?? ImageVideoUtils.selectMediaPickSetting; + final source = await selector(context); + if (source != null) { + if (source == MediaPickSetting.Gallery) { + _pickImage(context); + } else { + _typeLink(context); } - break; + } + } else { + _typeLink(context); } } diff --git a/lib/src/widgets/toolbar/image_video_utils.dart b/lib/src/widgets/toolbar/image_video_utils.dart index ef5d7afe..dd3a4859 100644 --- a/lib/src/widgets/toolbar/image_video_utils.dart +++ b/lib/src/widgets/toolbar/image_video_utils.dart @@ -5,13 +5,15 @@ import 'package:flutter/material.dart'; import 'package:image_picker/image_picker.dart'; import '../../models/documents/nodes/embed.dart'; -import '../../utils/media_source.dart'; +import '../../utils/media_pick_setting.dart'; import '../controller.dart'; import '../toolbar.dart'; class ImageVideoUtils { - static Future selectMediaSource(BuildContext context) => - showDialog( + static Future selectMediaPickSetting( + BuildContext context, + ) => + showDialog( context: context, builder: (ctx) => AlertDialog( contentPadding: EdgeInsets.zero, @@ -25,7 +27,7 @@ class ImageVideoUtils { color: Colors.orangeAccent, ), label: const Text('Gallery'), - onPressed: () => Navigator.pop(ctx, MediaSource.Gallery), + onPressed: () => Navigator.pop(ctx, MediaPickSetting.Gallery), ), TextButton.icon( icon: const Icon( @@ -33,7 +35,7 @@ class ImageVideoUtils { color: Colors.cyanAccent, ), label: const Text('Link'), - onPressed: () => Navigator.pop(ctx, MediaSource.Link), + onPressed: () => Navigator.pop(ctx, MediaPickSetting.Link), ) ], ), diff --git a/lib/src/widgets/toolbar/video_button.dart b/lib/src/widgets/toolbar/video_button.dart index 08f091f1..8f2c797d 100644 --- a/lib/src/widgets/toolbar/video_button.dart +++ b/lib/src/widgets/toolbar/video_button.dart @@ -2,7 +2,7 @@ import 'package:flutter/material.dart'; import 'package:image_picker/image_picker.dart'; import '../../models/documents/nodes/embed.dart'; -import '../../utils/media_source.dart'; +import '../../utils/media_pick_setting.dart'; import '../controller.dart'; import '../link_dialog.dart'; import '../toolbar.dart'; @@ -13,19 +13,14 @@ class VideoButton extends StatelessWidget { const VideoButton({ required this.icon, required this.controller, - required this.source, this.iconSize = kDefaultIconSize, this.onVideoPickCallback, this.fillColor, this.filePickImpl, this.webVideoPickImpl, - this.mediaSourceSelectorBuilder, + this.mediaPickSettingSelector, Key? key, - }) : assert( - source == MediaSource.Link || onVideoPickCallback != null, - 'Gallery source requires non-null onVideoPickCallback', - ), - super(key: key); + }) : super(key: key); final IconData icon; final double iconSize; @@ -40,9 +35,7 @@ class VideoButton extends StatelessWidget { final FilePickImpl? filePickImpl; - final MediaSource source; - - final MediaSourceSelectorBuilder? mediaSourceSelectorBuilder; + final MediaPickSettingSelector? mediaPickSettingSelector; @override Widget build(BuildContext context) { @@ -59,30 +52,19 @@ class VideoButton extends StatelessWidget { } Future _onPressedHandler(BuildContext context) async { - switch (source) { - case MediaSource.Gallery: - _pickVideo(context); - break; - case MediaSource.Link: - _typeLink(context); - break; - case MediaSource.GalleryAndLink: - final builder = - mediaSourceSelectorBuilder ?? ImageVideoUtils.selectMediaSource; - final source = await builder(context); - if (source != null) { - assert( - source != MediaSource.GalleryAndLink, - 'Source selector should return either MediaSource.Gallery or Link', - ); - - if (source == MediaSource.Gallery) { - _pickVideo(context); - } else { - _typeLink(context); - } + if (onVideoPickCallback != null) { + final selector = + mediaPickSettingSelector ?? ImageVideoUtils.selectMediaPickSetting; + final source = await selector(context); + if (source != null) { + if (source == MediaPickSetting.Gallery) { + _pickVideo(context); + } else { + _typeLink(context); } - break; + } + } else { + _typeLink(context); } }