Compare commits

...

3 Commits

  1. 6
      example/lib/screens/quill/my_quill_editor.dart
  2. 14
      example/macos/Podfile.lock
  3. 2
      example/macos/Runner/AppDelegate.swift
  4. 12
      flutter_quill_extensions/lib/embeds/embed_types.dart
  5. 277
      flutter_quill_extensions/lib/embeds/others/image_video_utils.dart
  6. 537
      flutter_quill_extensions/lib/embeds/others/media_button/media_button.dart
  7. 19
      flutter_quill_extensions/lib/embeds/unknown/editor/unknown_embed.dart
  8. 62
      flutter_quill_extensions/lib/flutter_quill_extensions.dart
  9. 71
      flutter_quill_extensions/lib/models/config/media/media_button_configurations.dart
  10. 0
      flutter_quill_extensions/lib/src/common/extensions/attribute.dart
  11. 0
      flutter_quill_extensions/lib/src/common/extensions/controller_ext.dart
  12. 122
      flutter_quill_extensions/lib/src/common/image_video_utils.dart
  13. 0
      flutter_quill_extensions/lib/src/common/utils/dart_ui/dart_ui_fake.dart
  14. 0
      flutter_quill_extensions/lib/src/common/utils/dart_ui/dart_ui_real.dart
  15. 0
      flutter_quill_extensions/lib/src/common/utils/element_utils/element_shared_utils.dart
  16. 0
      flutter_quill_extensions/lib/src/common/utils/element_utils/element_utils.dart
  17. 0
      flutter_quill_extensions/lib/src/common/utils/element_utils/element_web_utils.dart
  18. 0
      flutter_quill_extensions/lib/src/common/utils/patterns.dart
  19. 0
      flutter_quill_extensions/lib/src/common/utils/quill_image_utils.dart
  20. 0
      flutter_quill_extensions/lib/src/common/utils/quill_table_utils.dart
  21. 0
      flutter_quill_extensions/lib/src/common/utils/string.dart
  22. 4
      flutter_quill_extensions/lib/src/common/utils/utils.dart
  23. 0
      flutter_quill_extensions/lib/src/editor/formula/formula_embed.dart
  24. 8
      flutter_quill_extensions/lib/src/editor/image/image_embed.dart
  25. 4
      flutter_quill_extensions/lib/src/editor/image/image_embed_types.dart
  26. 16
      flutter_quill_extensions/lib/src/editor/image/image_menu.dart
  27. 10
      flutter_quill_extensions/lib/src/editor/image/image_web_embed.dart
  28. 2
      flutter_quill_extensions/lib/src/editor/image/models/image_configurations.dart
  29. 0
      flutter_quill_extensions/lib/src/editor/image/models/image_web_configurations.dart
  30. 6
      flutter_quill_extensions/lib/src/editor/image/widgets/image.dart
  31. 0
      flutter_quill_extensions/lib/src/editor/image/widgets/image_resizer.dart
  32. 0
      flutter_quill_extensions/lib/src/editor/table/table_cell_embed.dart
  33. 2
      flutter_quill_extensions/lib/src/editor/table/table_embed.dart
  34. 0
      flutter_quill_extensions/lib/src/editor/table/table_models.dart
  35. 0
      flutter_quill_extensions/lib/src/editor/video/models/video_configurations.dart
  36. 0
      flutter_quill_extensions/lib/src/editor/video/models/video_web_configurations.dart
  37. 0
      flutter_quill_extensions/lib/src/editor/video/models/youtube_video_support_mode.dart
  38. 10
      flutter_quill_extensions/lib/src/editor/video/video_embed.dart
  39. 10
      flutter_quill_extensions/lib/src/editor/video/video_web_embed.dart
  40. 2
      flutter_quill_extensions/lib/src/editor/video/widgets/video_app.dart
  41. 2
      flutter_quill_extensions/lib/src/editor/video/widgets/youtube_video_app.dart
  42. 0
      flutter_quill_extensions/lib/src/editor_toolbar_controller_shared/clipboard/super_clipboard_service.dart
  43. 0
      flutter_quill_extensions/lib/src/editor_toolbar_shared/image_picker/image_options.dart
  44. 0
      flutter_quill_extensions/lib/src/editor_toolbar_shared/image_picker/image_picker.dart
  45. 0
      flutter_quill_extensions/lib/src/editor_toolbar_shared/image_picker/packages/image_picker.dart
  46. 0
      flutter_quill_extensions/lib/src/editor_toolbar_shared/image_picker/s_image_picker.dart
  47. 0
      flutter_quill_extensions/lib/src/editor_toolbar_shared/image_saver/exceptions.dart
  48. 0
      flutter_quill_extensions/lib/src/editor_toolbar_shared/image_saver/image_saver.dart
  49. 0
      flutter_quill_extensions/lib/src/editor_toolbar_shared/image_saver/packages/gal.dart
  50. 0
      flutter_quill_extensions/lib/src/editor_toolbar_shared/image_saver/s_image_saver.dart
  51. 4
      flutter_quill_extensions/lib/src/editor_toolbar_shared/shared_configurations.dart
  52. 36
      flutter_quill_extensions/lib/src/flutter_quill_embeds.dart
  53. 6
      flutter_quill_extensions/lib/src/toolbar/camera/camera_button.dart
  54. 4
      flutter_quill_extensions/lib/src/toolbar/camera/camera_types.dart
  55. 2
      flutter_quill_extensions/lib/src/toolbar/camera/models/camera_configurations.dart
  56. 0
      flutter_quill_extensions/lib/src/toolbar/camera/select_camera_action.dart
  57. 2
      flutter_quill_extensions/lib/src/toolbar/formula/formula_button.dart
  58. 0
      flutter_quill_extensions/lib/src/toolbar/formula/models/formula_configurations.dart
  59. 10
      flutter_quill_extensions/lib/src/toolbar/image/image_button.dart
  60. 2
      flutter_quill_extensions/lib/src/toolbar/image/models/image_configurations.dart
  61. 2
      flutter_quill_extensions/lib/src/toolbar/image/select_image_source.dart
  62. 0
      flutter_quill_extensions/lib/src/toolbar/table/models/table_configurations.dart
  63. 5
      flutter_quill_extensions/lib/src/toolbar/table/table_button.dart
  64. 4
      flutter_quill_extensions/lib/src/toolbar/video/models/video.dart
  65. 2
      flutter_quill_extensions/lib/src/toolbar/video/models/video_configurations.dart
  66. 2
      flutter_quill_extensions/lib/src/toolbar/video/select_video_source.dart
  67. 10
      flutter_quill_extensions/lib/src/toolbar/video/video_button.dart

@ -7,10 +7,10 @@ import 'package:flutter/material.dart';
import 'package:flutter_quill/extensions.dart'
show isAndroid, isDesktop, isIOS, isWeb;
import 'package:flutter_quill/flutter_quill.dart';
import 'package:flutter_quill_extensions/embeds/widgets/image.dart'
show getImageProviderByImageSource, imageFileExtensions;
import 'package:flutter_quill_extensions/flutter_quill_extensions.dart';
import 'package:flutter_quill_extensions/models/config/video/editor/youtube_video_support_mode.dart';
// ignore: implementation_imports
import 'package:flutter_quill_extensions/src/editor/image/widgets/image.dart'
show getImageProviderByImageSource, imageFileExtensions;
import 'package:path/path.dart' as path;
import '../../extensions/scaffold_messenger.dart';

@ -18,8 +18,6 @@ PODS:
- path_provider_foundation (0.0.1):
- Flutter
- FlutterMacOS
- printing (1.0.0):
- FlutterMacOS
- share_plus (0.0.1):
- FlutterMacOS
- sqflite (0.0.3):
@ -42,7 +40,6 @@ DEPENDENCIES:
- gal (from `Flutter/ephemeral/.symlinks/plugins/gal/darwin`)
- irondash_engine_context (from `Flutter/ephemeral/.symlinks/plugins/irondash_engine_context/macos`)
- path_provider_foundation (from `Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin`)
- printing (from `Flutter/ephemeral/.symlinks/plugins/printing/macos`)
- share_plus (from `Flutter/ephemeral/.symlinks/plugins/share_plus/macos`)
- sqflite (from `Flutter/ephemeral/.symlinks/plugins/sqflite/darwin`)
- super_native_extensions (from `Flutter/ephemeral/.symlinks/plugins/super_native_extensions/macos`)
@ -70,8 +67,6 @@ EXTERNAL SOURCES:
:path: Flutter/ephemeral/.symlinks/plugins/irondash_engine_context/macos
path_provider_foundation:
:path: Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin
printing:
:path: Flutter/ephemeral/.symlinks/plugins/printing/macos
share_plus:
:path: Flutter/ephemeral/.symlinks/plugins/share_plus/macos
sqflite:
@ -86,19 +81,18 @@ EXTERNAL SOURCES:
SPEC CHECKSUMS:
desktop_drop: 69eeff437544aa619c8db7f4481b3a65f7696898
device_info_plus: ce1b7762849d3ec103d0e0517299f2db7ad60720
file_selector_macos: 468fb6b81fac7c0e88d71317f3eec34c3b008ff9
file_selector_macos: 54fdab7caa3ac3fc43c9fac4d7d8d231277f8cf2
flutter_inappwebview_macos: 9600c9df9fdb346aaa8933812009f8d94304203d
FlutterMacOS: 8f6f14fa908a6fb3fba0cd85dbd81ec4b251fb24
gal: 61e868295d28fe67ffa297fae6dacebf56fd53e1
irondash_engine_context: da62996ee25616d2f01bbeb85dc115d813359478
OrderedSet: aaeb196f7fef5a9edf55d89760da9176ad40b93c
path_provider_foundation: 3784922295ac71e43754bd15e0653ccfd36a147c
printing: 1dd6a1fce2209ec240698e2439a4adbb9b427637
path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46
share_plus: 36537c04ce0c3e3f5bd297ce4318b6d5ee5fd6cf
sqflite: 673a0e54cc04b7d6dba8d24fb8095b31c3a99eec
super_native_extensions: 85efee3a7495b46b04befcfc86ed12069264ebf3
url_launcher_macos: d2691c7dd33ed713bf3544850a623080ec693d95
video_player_avfoundation: 2b4384f3b157206b5e150a0083cdc0c905d260d3
url_launcher_macos: 5f437abeda8c85500ceb03f5c1938a8c5a705399
video_player_avfoundation: 7c6c11d8470e1675df7397027218274b6d2360b3
PODFILE CHECKSUM: 7159dd71cf9f57a5669bb2dee7a5030dbcc0483f

@ -1,7 +1,7 @@
import Cocoa
import FlutterMacOS
@NSApplicationMain
@main
class AppDelegate: FlutterAppDelegate {
override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool {
return true

@ -1,12 +0,0 @@
import 'package:cross_file/cross_file.dart' show XFile;
typedef MediaFileUrl = String;
typedef MediaFilePicker = Future<XFile?> Function(QuillMediaType mediaType);
typedef MediaPickedCallback = Future<MediaFileUrl> Function(XFile file);
enum QuillMediaType { image, video }
extension QuillMediaTypeX on QuillMediaType {
bool get isImage => this == QuillMediaType.image;
bool get isVideo => this == QuillMediaType.video;
}

@ -1,277 +0,0 @@
import 'package:flutter/material.dart';
import 'package:flutter_quill/flutter_quill.dart' show QuillDialogTheme;
import 'package:flutter_quill/translations.dart';
import '../../utils/patterns.dart';
enum LinkType {
video,
image,
}
class TypeLinkDialog extends StatefulWidget {
const TypeLinkDialog({
required this.linkType,
this.dialogTheme,
this.link,
this.linkRegExp,
super.key,
});
final QuillDialogTheme? dialogTheme;
final String? link;
final RegExp? linkRegExp;
final LinkType linkType;
@override
TypeLinkDialogState createState() => TypeLinkDialogState();
}
class TypeLinkDialogState extends State<TypeLinkDialog> {
late String _link;
late TextEditingController _controller;
RegExp? _linkRegExp;
@override
void initState() {
super.initState();
_link = widget.link ?? '';
_controller = TextEditingController(text: _link);
_linkRegExp = widget.linkRegExp;
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return AlertDialog(
backgroundColor: widget.dialogTheme?.dialogBackgroundColor,
content: TextField(
keyboardType: TextInputType.url,
textInputAction: TextInputAction.done,
maxLines: null,
style: widget.dialogTheme?.inputTextStyle,
decoration: InputDecoration(
labelText: context.loc.pasteLink,
hintText: widget.linkType == LinkType.image
? context.loc.pleaseEnterAValidImageURL
: context.loc.pleaseEnterAValidVideoURL,
labelStyle: widget.dialogTheme?.labelTextStyle,
floatingLabelStyle: widget.dialogTheme?.labelTextStyle,
),
autofocus: true,
onChanged: _linkChanged,
controller: _controller,
onEditingComplete: () {
if (!_canPress()) {
return;
}
_applyLink();
},
),
actions: [
TextButton(
onPressed: _canPress() ? _applyLink : null,
child: Text(
context.loc.ok,
style: widget.dialogTheme?.labelTextStyle,
),
),
],
);
}
void _linkChanged(String value) {
setState(() {
_link = value;
});
}
void _applyLink() {
Navigator.pop(context, _link.trim());
}
RegExp get linkRegExp {
final customRegExp = _linkRegExp;
if (customRegExp != null) {
return customRegExp;
}
switch (widget.linkType) {
case LinkType.video:
if (youtubeRegExp.hasMatch(_link)) {
return youtubeRegExp;
}
return videoRegExp;
case LinkType.image:
return imageRegExp;
}
}
bool _canPress() {
if (_link.isEmpty) {
return false;
}
if (widget.linkType == LinkType.image) {}
return _link.isNotEmpty && linkRegExp.hasMatch(_link);
}
}
// @immutable
// class ImageVideoUtils {
// const ImageVideoUtils._();
// static Future<MediaPickSetting?> selectMediaPickSetting(
// BuildContext context,
// ) =>
// showDialog<MediaPickSetting>(
// context: context,
// builder: (ctx) => AlertDialog(
// contentPadding: EdgeInsets.zero,
// content: Column(
// mainAxisSize: MainAxisSize.min,
// children: [
// TextButton.icon(
// icon: const Icon(
// Icons.collections,
// color: Colors.orangeAccent,
// ),
// label: Text('Gallery'.i18n),
// onPressed: () => Navigator.pop(ctx,
// MediaPickSetting.gallery),
// ),
// TextButton.icon(
// icon: const Icon(
// Icons.link,
// color: Colors.cyanAccent,
// ),
// label: Text('Link'.i18n),
// onPressed: () => Navigator.pop(ctx, MediaPickSetting.link),
// )
// ],
// ),
// ),
// );
// /// For image picking logic
// static Future<void> handleImageButtonTap(
// BuildContext context,
// QuillController controller,
// ImageSource imageSource,
// OnImagePickCallback onImagePickCallback, {
// FilePickImpl? filePickImpl,
// WebImagePickImpl? webImagePickImpl,
// }) async {
// String? imageUrl;
// if (kIsWeb) {
// if (webImagePickImpl != null) {
// imageUrl = await webImagePickImpl(onImagePickCallback);
// return;
// }
// final file = await ImagePicker()
//.pickImage(source: ImageSource.gallery);
// imageUrl = file?.path;
// if (imageUrl == null) {
// return;
// }
// } else if (isMobile()) {
// imageUrl = await _pickImage(imageSource, onImagePickCallback);
// } else {
// assert(filePickImpl != null, 'Desktop must provide filePickImpl');
// imageUrl =
// await _pickImageDesktop
//(context, filePickImpl!, onImagePickCallback);
// }
// if (imageUrl == null) {
// return;
// }
// controller.insertImageBlock(
// imageUrl: imageUrl,
// );
// }
// static Future<String?> _pickImage(
// ImageSource source,
// OnImagePickCallback onImagePickCallback,
// ) async {
// final pickedFile = await ImagePicker().pickImage(source: source);
// if (pickedFile == null) {
// return null;
// }
// return onImagePickCallback(File(pickedFile.path));
// }
// static Future<String?> _pickImageDesktop(
// BuildContext context,
// FilePickImpl filePickImpl,
// OnImagePickCallback onImagePickCallback,
// ) async {
// final filePath = await filePickImpl(context);
// if (filePath == null || filePath.isEmpty) return null;
// final file = File(filePath);
// return onImagePickCallback(file);
// }
// /// For video picking logic
// static Future<void> handleVideoButtonTap(
// BuildContext context,
// QuillController controller,
// ImageSource videoSource,
// OnVideoPickCallback onVideoPickCallback, {
// FilePickImpl? filePickImpl,
// WebVideoPickImpl? webVideoPickImpl,
// }) async {
// final index = controller.selection.baseOffset;
// final length = controller.selection.extentOffset - index;
// String? videoUrl;
// if (kIsWeb) {
// assert(
// webVideoPickImpl != null,
// 'Please provide webVideoPickImpl for Web '
// 'in the options of this button',
// );
// videoUrl = await webVideoPickImpl!(onVideoPickCallback);
// } else if (isMobile()) {
// videoUrl = await _pickVideo(videoSource, onVideoPickCallback);
// } else {
// assert(filePickImpl != null, 'Desktop must provide filePickImpl');
// videoUrl =
// await _pickVideoDesktop(context, filePickImpl!,
// onVideoPickCallback);
// }
// if (videoUrl != null) {
// controller.replaceText(index, length, BlockEmbed.video(videoUrl),
// null);
// }
// }
// static Future<String?> _pickVideo(
// ImageSource source, OnVideoPickCallback onVideoPickCallback) async {
// final pickedFile = await ImagePicker().pickVideo(source: source);
// if (pickedFile == null) {
// return null;
// }
// return onVideoPickCallback(File(pickedFile.path));
// }
// static Future<String?> _pickVideoDesktop(
// BuildContext context,
// FilePickImpl filePickImpl,
// OnVideoPickCallback onVideoPickCallback) async {
// final filePath = await filePickImpl(context);
// if (filePath == null || filePath.isEmpty) return null;
// final file = File(filePath);
// return onVideoPickCallback(file);
// }
// }

@ -1,537 +0,0 @@
// // ignore_for_file: use_build_context_synchronously
// import 'dart:math' as math;
// import 'dart:ui';
// import 'package:flutter/foundation.dart';
// import 'package:flutter/material.dart';
// import 'package:flutter_quill/extensions.dart';
// import 'package:flutter_quill/flutter_quill.dart';
// import 'package:flutter_quill/translations.dart';
// import 'package:image_picker/image_picker.dart';
// import '../../../models/config/toolbar/buttons/media_button.dart';
// import '../../embed_types.dart';
// import '../utils/image_video_utils.dart';
// /// Widget which combines [ImageButton] and [VideButton] widgets. This widget
// /// has more customization and uses dialog similar to one which is used
// /// on [http://quilljs.com].
// class QuillToolbarMediaButton extends StatelessWidget {
// QuillToolbarMediaButton({
// required this.controller,
// this.options,
// super.key,
// }) : assert(options.type == QuillMediaType.image,
// 'Video selection is not supported yet');
// final QuillController controller;
// final QuillToolbarMediaButtonOptions options;
// double _iconSize(BuildContext context) {
// final baseFontSize = baseButtonExtraOptions(context).globalIconSize;
// final iconSize = options.iconSize;
// return iconSize ?? baseFontSize;
// }
// VoidCallback? _afterButtonPressed(BuildContext context) {
// return options.afterButtonPressed ??
// baseButtonExtraOptions(context).afterButtonPressed;
// }
// QuillIconTheme? _iconTheme(BuildContext context) {
// return options.iconTheme ?? baseButtonExtraOptions(context).iconTheme;
// }
// QuillToolbarBaseButtonOptions baseButtonExtraOptions(
//BuildContext context) {
// return context.requireQuillToolbarBaseButtonOptions;
// }
// (IconData, String) get _defaultData {
// switch (options.type) {
// case QuillMediaType.image:
// return (Icons.perm_media, 'Photo media button');
// case QuillMediaType.video:
// throw UnsupportedError('The video is not supported yet.');
// }
// }
// IconData _iconData(BuildContext context) {
// return options.iconData ??
// baseButtonExtraOptions(context).iconData ??
// _defaultData.$1;
// }
// String _tooltip(BuildContext context) {
// return options.tooltip ??
// baseButtonExtraOptions(context).tooltip ??
// _defaultData.$2;
// // ('Camera'.i18n);
// }
// void _sharedOnPressed(BuildContext context) {
// _onPressedHandler(context);
// _afterButtonPressed(context);
// }
// @override
// Widget build(BuildContext context) {
// final tooltip = _tooltip(context);
// final iconSize = _iconSize(context);
// final iconData = _iconData(context);
// final childBuilder =
// options.childBuilder ?? baseButtonExtraOptions(context).childBuilder;
// final iconTheme = _iconTheme(context);
// if (childBuilder != null) {
// return childBuilder(
// QuillToolbarMediaButtonOptions(
// type: options.type,
// onMediaPickedCallback: options.onMediaPickedCallback,
// onImagePickCallback: options.onImagePickCallback,
// onVideoPickCallback: options.onVideoPickCallback,
// iconData: iconData,
// afterButtonPressed: _afterButtonPressed(context),
// autovalidateMode: options.autovalidateMode,
// childrenSpacing: options.childrenSpacing,
// dialogBarrierColor: options.dialogBarrierColor,
// dialogTheme: options.dialogTheme,
// filePickImpl: options.filePickImpl,
// fillColor: options.fillColor,
// galleryButtonText: options.galleryButtonText,
// iconTheme: iconTheme,
// iconSize: iconSize,
// iconButtonFactor: iconButtonFactor,
// hintText: options.hintText,
// labelText: options.labelText,
// submitButtonSize: options.submitButtonSize,
// linkButtonText: options.linkButtonText,
// mediaFilePicker: options.mediaFilePicker,
// submitButtonText: options.submitButtonText,
// validationMessage: options.validationMessage,
// webImagePickImpl: options.webImagePickImpl,
// webVideoPickImpl: options.webVideoPickImpl,
// tooltip: options.tooltip,
// ),
// QuillToolbarMediaButtonExtraOptions(
// context: context,
// controller: controller,
// onPressed: () => _sharedOnPressed(context),
// ),
// );
// }
// final theme = Theme.of(context);
// final iconColor =
// options.iconTheme?.iconUnselectedColor ?? theme.iconTheme.color;
// final iconFillColor = options.iconTheme?.iconUnselectedFillColor ??
// options.fillColor ??
// theme.canvasColor;
// return QuillToolbarIconButton(
// icon: Icon(iconData, size: iconSize, color: iconColor),
// tooltip: tooltip,
// highlightElevation: 0,
// hoverElevation: 0,
// size: iconSize * iconButtonFactor,
// fillColor: iconFillColor,
// borderRadius: iconTheme?.borderRadius ?? 2,
// onPressed: () => _sharedOnPressed(context),
// );
// }
// Future<void> _onPressedHandler(BuildContext context) async {
// if (options.onMediaPickedCallback == null) {
// _inputLink(context);
// return;
// }
// final mediaSource = await showDialog<MediaPickSetting>(
// context: context,
// builder: (_) => MediaSourceSelectorDialog(
// dialogTheme: options.dialogTheme,
// galleryButtonText: options.galleryButtonText,
// linkButtonText: options.linkButtonText,
// ),
// );
// if (mediaSource == null) {
// return;
// }
// switch (mediaSource) {
// case MediaPickSetting.gallery:
// await _pickImage();
// break;
// case MediaPickSetting.link:
// _inputLink(context);
// break;
// case MediaPickSetting.camera:
// await ImageVideoUtils.handleImageButtonTap(
// context,
// controller,
// ImageSource.camera,
// options.onImagePickCallback,
// filePickImpl: options.filePickImpl,
// webImagePickImpl: options.webImagePickImpl,
// );
// break;
// case MediaPickSetting.video:
// await ImageVideoUtils.handleVideoButtonTap(
// context,
// controller,
// ImageSource.camera,
// options.onVideoPickCallback,
// filePickImpl: options.filePickImpl,
// webVideoPickImpl: options.webVideoPickImpl,
// );
// break;
// }
// }
// Future<void> _pickImage() async {
// if (!(kIsWeb || isMobile() || isDesktop())) {
// throw UnsupportedError(
// 'Unsupported target platform: ${defaultTargetPlatform.name}',
// );
// }
// final mediaFileUrl = await _pickMediaFileUrl();
// if (mediaFileUrl != null) {
// final index = controller.selection.baseOffset;
// final length = controller.selection.extentOffset - index;
// controller.replaceText(
// index,
// length,
// BlockEmbed.image(mediaFileUrl),
// null,
// );
// }
// }
// Future<MediaFileUrl?> _pickMediaFileUrl() async {
// final mediaFile = await options.mediaFilePicker?.call(options.type);
// return mediaFile != null
// ? options.onMediaPickedCallback?.call(mediaFile)
// : null;
// }
// void _inputLink(BuildContext context) {
// showDialog<String>(
// context: context,
// builder: (_) => MediaLinkDialog(
// dialogTheme: options.dialogTheme,
// labelText: options.labelText,
// hintText: options.hintText,
// buttonText: options.submitButtonText,
// buttonSize: options.submitButtonSize,
// childrenSpacing: options.childrenSpacing,
// autovalidateMode: options.autovalidateMode,
// validationMessage: options.validationMessage,
// ),
// ).then(_linkSubmitted);
// }
// void _linkSubmitted(String? value) {
// if (value != null && value.isNotEmpty) {
// final index = controller.selection.baseOffset;
// final length = controller.selection.extentOffset - index;
// final data = options.type.isImage
// ? BlockEmbed.image(value)
// : BlockEmbed.video(value);
// controller.replaceText(index, length, data, null);
// }
// }
// }
// /// Provides a dialog for input link to media resource.
// class MediaLinkDialog extends StatefulWidget {
// const MediaLinkDialog({
// super.key,
// this.link,
// this.dialogTheme,
// this.childrenSpacing = 16.0,
// this.labelText,
// this.hintText,
// this.buttonText,
// this.buttonSize,
// this.autovalidateMode = AutovalidateMode.disabled,
// this.validationMessage,
// }) : assert(childrenSpacing > 0);
// final String? link;
// final QuillDialogTheme? dialogTheme;
// /// The margin between child widgets in the dialog.
// final double childrenSpacing;
// /// The text of label in link add mode.
// final String? labelText;
// /// The hint text for link [TextField].
// final String? hintText;
// /// The text of the submit button.
// final String? buttonText;
// /// The size of dialog buttons.
// final Size? buttonSize;
// final AutovalidateMode autovalidateMode;
// final String? validationMessage;
// @override
// State<MediaLinkDialog> createState() => _MediaLinkDialogState();
// }
// class _MediaLinkDialogState extends State<MediaLinkDialog> {
// final _linkFocus = FocusNode();
// final _linkController = TextEditingController();
// @override
// void dispose() {
// _linkFocus.dispose();
// _linkController.dispose();
// super.dispose();
// }
// @override
// Widget build(BuildContext context) {
// final constraints = widget.dialogTheme?.linkDialogConstraints ??
// () {
// final size = MediaQuery.sizeOf(context);
// final maxWidth = kIsWeb ? size.width / 4 : size.width - 80;
// return BoxConstraints(maxWidth: maxWidth, maxHeight: 80);
// }();
// final buttonStyle = widget.buttonSize != null
// ? Theme.of(context)
// .elevatedButtonTheme
// .style
// ?.copyWith(
//fixedSize: MaterialStatePropertyAll(widget.buttonSize))
// : widget.dialogTheme?.buttonStyle;
// final isWrappable = widget.dialogTheme?.isWrappable ?? false;
// final children = [
// Text(widget.labelText ?? 'Enter media'.i18n),
// UtilityWidgets.maybeWidget(
// enabled: !isWrappable,
// wrapper: (child) => Expanded(
// child: child,
// ),
// child: Padding(
// padding: EdgeInsets.symmetric(horizontal: widget.childrenSpacing),
// child: TextFormField(
// controller: _linkController,
// focusNode: _linkFocus,
// style: widget.dialogTheme?.inputTextStyle,
// keyboardType: TextInputType.url,
// textInputAction: TextInputAction.done,
// decoration: InputDecoration(
// labelStyle: widget.dialogTheme?.labelTextStyle,
// hintText: widget.hintText,
// ),
// autofocus: true,
// autovalidateMode: widget.autovalidateMode,
// validator: _validateLink,
// onChanged: _linkChanged,
// ),
// ),
// ),
// ElevatedButton(
// onPressed: _canPress() ? _submitLink : null,
// style: buttonStyle,
// child: Text(widget.buttonText ?? 'Ok'.i18n),
// ),
// ];
// return Dialog(
// backgroundColor: widget.dialogTheme?.dialogBackgroundColor,
// shape: widget.dialogTheme?.shape ??
// DialogTheme.of(context).shape ??
// RoundedRectangleBorder(borderRadius: BorderRadius.circular(4)),
// child: ConstrainedBox(
// constraints: constraints,
// child: Padding(
// padding:
// widget.dialogTheme?.linkDialogPadding ?? const
// EdgeInsets.all(16),
// child: Form(
// child: isWrappable
// ? Wrap(
// alignment: WrapAlignment.center,
// crossAxisAlignment: WrapCrossAlignment.center,
// runSpacing: widget.dialogTheme?.runSpacing ?? 0.0,
// children: children,
// )
// : Row(
// children: children,
// ),
// ),
// ),
// ),
// );
// }
// bool _canPress() => _validateLink(_linkController.text) == null;
// void _linkChanged(String value) {
// setState(() {
// _linkController.text = value;
// });
// }
// void _submitLink() => Navigator.pop(context, _linkController.text);
// String? _validateLink(String? value) {
// if ((value?.isEmpty ?? false) ||
// !AutoFormatMultipleLinksRule.oneLineLinkRegExp.hasMatch(value!)) {
// return widget.validationMessage ?? 'That is not a valid URL';
// }
// return null;
// }
// }
// /// Media souce selector.
// class MediaSourceSelectorDialog extends StatelessWidget {
// const MediaSourceSelectorDialog({
// super.key,
// this.dialogTheme,
// this.galleryButtonText,
// this.linkButtonText,
// });
// final QuillDialogTheme? dialogTheme;
// /// The text of the gallery button [MediaSourceSelectorDialog].
// final String? galleryButtonText;
// /// The text of the link button [MediaSourceSelectorDialog].
// final String? linkButtonText;
// @override
// Widget build(BuildContext context) {
// final constraints = dialogTheme?.mediaSelectorDialogConstraints ??
// () {
// final size = MediaQuery.sizeOf(context);
// double maxWidth, maxHeight;
// if (kIsWeb) {
// maxWidth = size.width / 7;
// maxHeight = size.height / 7;
// } else {
// maxWidth = size.width - 80;
// maxHeight = maxWidth / 2;
// }
// return BoxConstraints(maxWidth: maxWidth, maxHeight: maxHeight);
// }();
// final shape = dialogTheme?.shape ??
// DialogTheme.of(context).shape ??
// RoundedRectangleBorder(borderRadius: BorderRadius.circular(4));
// return Dialog(
// backgroundColor: dialogTheme?.dialogBackgroundColor,
// shape: shape,
// child: ConstrainedBox(
// constraints: constraints,
// child: Padding(
// padding: dialogTheme?.mediaSelectorDialogPadding ??
// const EdgeInsets.all(16),
// child: Row(
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
// children: [
// Expanded(
// child: TextButtonWithIcon(
// icon: Icons.collections,
// label: galleryButtonText ?? 'Gallery'.i18n,
// onPressed: () =>
// Navigator.pop(context, MediaPickSetting.gallery),
// ),
// ),
// const SizedBox(width: 10),
// Expanded(
// child: TextButtonWithIcon(
// icon: Icons.link,
// label: linkButtonText ?? 'Link'.i18n,
// onPressed: () =>
// Navigator.pop(context, MediaPickSetting.link),
// ),
// )
// ],
// ),
// ),
// ),
// );
// }
// }
// class TextButtonWithIcon extends StatelessWidget {
// const TextButtonWithIcon({
// required this.label,
// required this.icon,
// required this.onPressed,
// this.textStyle,
// super.key,
// });
// final String label;
// final IconData icon;
// final VoidCallback onPressed;
// final TextStyle? textStyle;
// @override
// Widget build(BuildContext context) {
// final theme = Theme.of(context);
// final scale = MediaQuery.maybeOf(context)?.textScaleFactor ?? 1;
// final gap = scale <= 1 ? 8.0 : lerpDouble(8, 4, math.min(scale - 1, 1))!;
// final buttonStyle = TextButtonTheme.of(context).style;
// final shape = buttonStyle?.shape?.resolve({}) ??
// const RoundedRectangleBorder(
// borderRadius: BorderRadius.all(
// Radius.circular(4),
// ),
// );
// return Material(
// shape: shape,
// textStyle: textStyle ??
// theme.textButtonTheme.style?.textStyle?.resolve({}) ??
// theme.textTheme.labelLarge,
// elevation: buttonStyle?.elevation?.resolve({}) ?? 0,
// child: InkWell(
// customBorder: shape,
// onTap: onPressed,
// child: Padding(
// padding: const EdgeInsets.all(16),
// child: Column(
// mainAxisSize: MainAxisSize.min,
// children: <Widget>[
// Icon(icon),
// SizedBox(height: gap),
// Flexible(child: Text(label)),
// ],
// ),
// ),
// ),
// );
// }
// }
// /// Default file picker.
// // Future<QuillFile?> _defaultMediaPicker(QuillMediaType mediaType) async {
// // final pickedFile = mediaType.isImage
// // ? await ImagePicker().pickImage(source: ImageSource.gallery)
// // : await ImagePicker().pickVideo(source: ImageSource.gallery);
// // if (pickedFile != null) {
// // return QuillFile(
// // name: pickedFile.name,
// // path: pickedFile.path,
// // bytes: await pickedFile.readAsBytes(),
// // );
// // }
// // return null;
// // }

@ -1,19 +0,0 @@
import 'package:flutter/widgets.dart';
import 'package:flutter_quill/flutter_quill.dart';
class QuillEditorUnknownEmbedBuilder extends EmbedBuilder {
@override
Widget build(
BuildContext context,
QuillController controller,
Embed node,
bool readOnly,
bool inline,
TextStyle textStyle,
) {
return const Text('Unknown embed builder');
}
@override
String get key => 'unknown';
}

@ -4,42 +4,38 @@ library flutter_quill_extensions;
import 'package:flutter_quill/src/editor_toolbar_controller_shared/clipboard/clipboard_service_provider.dart';
import 'package:meta/meta.dart' show immutable;
import 'services/clipboard/super_clipboard_service.dart';
import 'src/editor_toolbar_controller_shared/clipboard/super_clipboard_service.dart';
export 'embeds/embed_types.dart';
export 'embeds/formula/toolbar/formula_button.dart';
export 'embeds/image/editor/image_embed.dart';
export 'embeds/image/editor/image_embed_types.dart';
export 'embeds/image/editor/image_web_embed.dart';
export 'embeds/image/toolbar/image_button.dart';
export 'embeds/others/camera_button/camera_button.dart';
export 'embeds/others/media_button/media_button.dart';
export 'embeds/table/editor/table_cell_embed.dart';
export 'embeds/table/editor/table_embed.dart';
export 'embeds/table/editor/table_models.dart';
export 'embeds/table/toolbar/table_button.dart';
export 'embeds/unknown/editor/unknown_embed.dart';
export 'embeds/video/editor/video_embed.dart';
export 'embeds/video/editor/video_web_embed.dart';
export 'embeds/video/toolbar/video_button.dart';
export 'embeds/video/video.dart';
export 'extensions/controller_ext.dart';
export 'flutter_quill_embeds.dart';
export 'models/config/camera/camera_configurations.dart';
export 'models/config/formula/formula_configurations.dart';
export 'models/config/image/editor/image_configurations.dart';
export 'models/config/image/editor/image_web_configurations.dart';
export 'models/config/image/toolbar/image_configurations.dart';
export 'models/config/media/media_button_configurations.dart';
export 'models/config/shared_configurations.dart';
export 'models/config/table/table_configurations.dart';
export 'models/config/video/editor/video_configurations.dart';
export 'models/config/video/editor/video_web_configurations.dart';
export 'models/config/video/toolbar/video_configurations.dart';
export 'utils/utils.dart';
export 'src/common/extensions/controller_ext.dart';
export 'src/common/utils/utils.dart';
export 'src/editor/image/image_embed.dart';
export 'src/editor/image/image_embed_types.dart';
export 'src/editor/image/image_web_embed.dart';
export 'src/editor/image/models/image_configurations.dart';
export 'src/editor/image/models/image_web_configurations.dart';
export 'src/editor/table/table_cell_embed.dart';
export 'src/editor/table/table_embed.dart';
export 'src/editor/table/table_models.dart';
export 'src/editor/video/models/video_configurations.dart';
export 'src/editor/video/models/video_web_configurations.dart';
export 'src/editor/video/models/youtube_video_support_mode.dart';
export 'src/editor/video/video_embed.dart';
export 'src/editor/video/video_web_embed.dart';
export 'src/editor_toolbar_shared/shared_configurations.dart';
export 'src/flutter_quill_embeds.dart';
export 'src/toolbar/camera/camera_button.dart';
export 'src/toolbar/camera/models/camera_configurations.dart';
export 'src/toolbar/formula/formula_button.dart';
export 'src/toolbar/formula/models/formula_configurations.dart';
export 'src/toolbar/image/image_button.dart';
export 'src/toolbar/image/models/image_configurations.dart';
export 'src/toolbar/table/models/table_configurations.dart';
export 'src/toolbar/table/table_button.dart';
export 'src/toolbar/video/models/video.dart';
export 'src/toolbar/video/models/video_configurations.dart';
export 'src/toolbar/video/video_button.dart';
// TODO: Refactor flutter_quill_extensions to match the structure of flutter_quill
// Also avoid exposing all APIs as public. Use `src` as directory name
@immutable
class FlutterQuillExtensions {

@ -1,71 +0,0 @@
import 'package:flutter/widgets.dart' show AutovalidateMode;
import 'package:flutter/widgets.dart' show Color, Size;
import 'package:flutter_quill/flutter_quill.dart';
import '../../../embeds/embed_types.dart';
class QuillToolbarMediaButtonExtraOptions
extends QuillToolbarBaseButtonExtraOptions {
const QuillToolbarMediaButtonExtraOptions({
required super.controller,
required super.context,
required super.onPressed,
});
}
class QuillToolbarMediaButtonOptions extends QuillToolbarBaseButtonOptions<
QuillToolbarMediaButtonOptions, QuillToolbarMediaButtonExtraOptions> {
const QuillToolbarMediaButtonOptions({
required this.type,
required this.onMediaPickedCallback,
// required this.onVideoPickCallback,
this.dialogBarrierColor,
this.mediaFilePicker,
this.childrenSpacing = 16.0,
this.autovalidateMode = AutovalidateMode.disabled,
super.iconSize,
this.dialogTheme,
this.labelText,
this.hintText,
this.submitButtonText,
this.submitButtonSize,
this.galleryButtonText,
this.linkButtonText,
this.validationMessage,
super.iconData,
super.afterButtonPressed,
super.tooltip,
super.iconTheme,
super.childBuilder,
});
final QuillMediaType type;
final QuillDialogTheme? dialogTheme;
final MediaFilePicker? mediaFilePicker;
final MediaPickedCallback? onMediaPickedCallback;
final Color? dialogBarrierColor;
/// The margin between child widgets in the dialog.
final double childrenSpacing;
/// The text of label in link add mode.
final String? labelText;
/// The hint text for link [TextField].
final String? hintText;
/// The text of the submit button.
final String? submitButtonText;
/// The size of dialog buttons.
final Size? submitButtonSize;
/// The text of the gallery button [MediaSourceSelectorDialog].
final String? galleryButtonText;
/// The text of the link button [MediaSourceSelectorDialog].
final String? linkButtonText;
final AutovalidateMode autovalidateMode;
final String? validationMessage;
}

@ -0,0 +1,122 @@
import 'package:flutter/material.dart';
import 'package:flutter_quill/flutter_quill.dart' show QuillDialogTheme;
import 'package:flutter_quill/translations.dart';
import 'utils/patterns.dart';
enum LinkType {
video,
image,
}
class TypeLinkDialog extends StatefulWidget {
const TypeLinkDialog({
required this.linkType,
this.dialogTheme,
this.link,
this.linkRegExp,
super.key,
});
final QuillDialogTheme? dialogTheme;
final String? link;
final RegExp? linkRegExp;
final LinkType linkType;
@override
TypeLinkDialogState createState() => TypeLinkDialogState();
}
class TypeLinkDialogState extends State<TypeLinkDialog> {
late String _link;
late TextEditingController _controller;
RegExp? _linkRegExp;
@override
void initState() {
super.initState();
_link = widget.link ?? '';
_controller = TextEditingController(text: _link);
_linkRegExp = widget.linkRegExp;
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return AlertDialog(
backgroundColor: widget.dialogTheme?.dialogBackgroundColor,
content: TextField(
keyboardType: TextInputType.url,
textInputAction: TextInputAction.done,
maxLines: null,
style: widget.dialogTheme?.inputTextStyle,
decoration: InputDecoration(
labelText: context.loc.pasteLink,
hintText: widget.linkType == LinkType.image
? context.loc.pleaseEnterAValidImageURL
: context.loc.pleaseEnterAValidVideoURL,
labelStyle: widget.dialogTheme?.labelTextStyle,
floatingLabelStyle: widget.dialogTheme?.labelTextStyle,
),
autofocus: true,
onChanged: _linkChanged,
controller: _controller,
onEditingComplete: () {
if (!_canPress()) {
return;
}
_applyLink();
},
),
actions: [
TextButton(
onPressed: _canPress() ? _applyLink : null,
child: Text(
context.loc.ok,
style: widget.dialogTheme?.labelTextStyle,
),
),
],
);
}
void _linkChanged(String value) {
setState(() {
_link = value;
});
}
void _applyLink() {
Navigator.pop(context, _link.trim());
}
RegExp get linkRegExp {
final customRegExp = _linkRegExp;
if (customRegExp != null) {
return customRegExp;
}
switch (widget.linkType) {
case LinkType.video:
if (youtubeRegExp.hasMatch(_link)) {
return youtubeRegExp;
}
return videoRegExp;
case LinkType.image:
return imageRegExp;
}
}
bool _canPress() {
if (_link.isEmpty) {
return false;
}
if (widget.linkType == LinkType.image) {}
return _link.isNotEmpty && linkRegExp.hasMatch(_link);
}
}

@ -4,8 +4,8 @@ import 'package:cross_file/cross_file.dart';
import 'package:flutter/foundation.dart' show Uint8List, immutable;
import 'package:http/http.dart' as http;
import '../embeds/widgets/image.dart';
import '../services/image_saver/s_image_saver.dart';
import '../../editor/image/widgets/image.dart';
import '../../editor_toolbar_shared/image_saver/s_image_saver.dart';
import 'patterns.dart';
bool isBase64(String str) {

@ -2,11 +2,11 @@ import 'package:flutter/material.dart';
import 'package:flutter_quill/flutter_quill.dart' hide OptionalSize;
import 'package:flutter_quill/translations.dart';
import '../../../models/config/image/editor/image_configurations.dart';
import '../../../models/config/shared_configurations.dart';
import '../../../utils/element_utils/element_utils.dart';
import '../../widgets/image.dart';
import '../../common/utils/element_utils/element_utils.dart';
import '../../editor_toolbar_shared/shared_configurations.dart';
import 'image_menu.dart';
import 'models/image_configurations.dart';
import 'widgets/image.dart';
class QuillEditorImageEmbedBuilder extends EmbedBuilder {
QuillEditorImageEmbedBuilder({

@ -4,8 +4,8 @@ import 'package:flutter/widgets.dart' show BuildContext;
import 'package:flutter_quill/flutter_quill.dart';
import 'package:meta/meta.dart' show immutable;
import '../../../extensions/controller_ext.dart';
import '../../../services/image_picker/s_image_picker.dart';
import '../../common/extensions/controller_ext.dart';
import '../../editor_toolbar_shared/image_picker/s_image_picker.dart';
/// When request picking an image, for example when the image button toolbar
/// clicked, it should be null in case the user didn't choose any image or

@ -7,14 +7,14 @@ import 'package:flutter_quill/flutter_quill.dart'
import 'package:flutter_quill/translations.dart';
import 'package:super_clipboard/super_clipboard.dart';
import '../../../models/config/image/editor/image_configurations.dart';
import '../../../models/config/shared_configurations.dart';
import '../../../services/image_saver/s_image_saver.dart';
import '../../../utils/element_utils/element_utils.dart';
import '../../../utils/string.dart';
import '../../../utils/utils.dart';
import '../../widgets/image.dart' show ImageTapWrapper, getImageStyleString;
import '../../widgets/image_resizer.dart' show ImageResizer;
import '../../common/utils/element_utils/element_utils.dart';
import '../../common/utils/string.dart';
import '../../common/utils/utils.dart';
import '../../editor_toolbar_shared/image_saver/s_image_saver.dart';
import '../../editor_toolbar_shared/shared_configurations.dart';
import 'models/image_configurations.dart';
import 'widgets/image.dart' show ImageTapWrapper, getImageStyleString;
import 'widgets/image_resizer.dart' show ImageResizer;
class ImageOptionsMenu extends StatelessWidget {
const ImageOptionsMenu({

@ -3,12 +3,12 @@ import 'package:flutter/widgets.dart';
import 'package:flutter_quill/flutter_quill.dart';
import 'package:universal_html/html.dart' as html;
import '../../../models/config/image/editor/image_web_configurations.dart';
import '../../../utils/dart_ui/dart_ui_fake.dart'
if (dart.library.js_interop) '../../../utils/dart_ui/dart_ui_real.dart'
import '../../common/utils/dart_ui/dart_ui_fake.dart'
if (dart.library.js_interop) '../../common/utils/dart_ui/dart_ui_real.dart'
as ui;
import '../../../utils/element_utils/element_web_utils.dart';
import '../../../utils/utils.dart';
import '../../common/utils/element_utils/element_web_utils.dart';
import '../../common/utils/utils.dart';
import 'models/image_web_configurations.dart';
class QuillEditorWebImageEmbedBuilder extends EmbedBuilder {
const QuillEditorWebImageEmbedBuilder({

@ -3,7 +3,7 @@ import 'dart:io' show File;
import 'package:flutter_quill/extensions.dart';
import 'package:meta/meta.dart' show immutable;
import '../../../../embeds/image/editor/image_embed_types.dart';
import '../image_embed_types.dart';
/// [QuillEditorImageEmbedConfigurations] for desktop, mobile and
/// other platforms

@ -6,9 +6,9 @@ import 'package:flutter/material.dart';
import 'package:flutter_quill/flutter_quill.dart';
import 'package:photo_view/photo_view.dart';
import '../../models/config/image/editor/image_configurations.dart';
import '../../utils/utils.dart';
import '../image/editor/image_embed_types.dart';
import '../../../common/utils/utils.dart';
import '../image_embed_types.dart';
import '../models/image_configurations.dart';
const List<String> imageFileExtensions = [
'.jpeg',

@ -3,7 +3,7 @@ import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter_quill/flutter_quill.dart';
import 'package:flutter_quill/quill_delta.dart';
import '../../../utils/quill_table_utils.dart';
import '../../common/utils/quill_table_utils.dart';
import 'table_cell_embed.dart';
import 'table_models.dart';

@ -2,11 +2,11 @@ import 'package:flutter/foundation.dart' show kIsWeb;
import 'package:flutter/material.dart';
import 'package:flutter_quill/flutter_quill.dart';
import '../../../models/config/video/editor/video_configurations.dart';
import '../../../utils/element_utils/element_utils.dart';
import '../../../utils/utils.dart';
import '../../widgets/video_app.dart';
import '../../widgets/youtube_video_app.dart';
import '../../common/utils/element_utils/element_utils.dart';
import '../../common/utils/utils.dart';
import 'models/video_configurations.dart';
import 'widgets/video_app.dart';
import 'widgets/youtube_video_app.dart';
class QuillEditorVideoEmbedBuilder extends EmbedBuilder {
const QuillEditorVideoEmbedBuilder({

@ -4,12 +4,12 @@ import 'package:universal_html/html.dart' as html;
import 'package:youtube_player_flutter/youtube_player_flutter.dart'
show YoutubePlayer;
import '../../../models/config/video/editor/video_web_configurations.dart';
import '../../../utils/dart_ui/dart_ui_fake.dart'
if (dart.library.js_interop) '../../../utils/dart_ui/dart_ui_real.dart'
import '../../common/utils/dart_ui/dart_ui_fake.dart'
if (dart.library.js_interop) '../../common/utils/dart_ui/dart_ui_real.dart'
as ui;
import '../../../utils/element_utils/element_web_utils.dart';
import '../../../utils/utils.dart';
import '../../common/utils/element_utils/element_web_utils.dart';
import '../../common/utils/utils.dart';
import 'models/video_web_configurations.dart';
class QuillEditorWebVideoEmbedBuilder extends EmbedBuilder {
const QuillEditorWebVideoEmbedBuilder({

@ -6,7 +6,7 @@ import 'package:flutter_quill/flutter_quill.dart';
import 'package:url_launcher/url_launcher.dart';
import 'package:video_player/video_player.dart';
import '../../flutter_quill_extensions.dart';
import '../../../../flutter_quill_extensions.dart';
/// Widget for playing back video
/// Refer to https://github.com/flutter/plugins/tree/master/packages/video_player/video_player

@ -5,7 +5,7 @@ import 'package:url_launcher/url_launcher_string.dart';
import 'package:youtube_explode_dart/youtube_explode_dart.dart';
import 'package:youtube_player_flutter/youtube_player_flutter.dart';
import '../../models/config/video/editor/youtube_video_support_mode.dart';
import '../models/youtube_video_support_mode.dart';
import 'video_app.dart';
class YoutubeVideoApp extends StatefulWidget {

@ -2,8 +2,8 @@ import 'package:flutter/widgets.dart' show BuildContext;
import 'package:flutter_quill/flutter_quill.dart';
import 'package:meta/meta.dart' show immutable;
import '../../services/image_picker/s_image_picker.dart';
import '../../services/image_saver/s_image_saver.dart';
import 'image_picker/s_image_picker.dart';
import 'image_saver/s_image_saver.dart';
/// Configurations for Flutter Editor Extensions
/// shared between toolbar and editor

@ -2,23 +2,21 @@ import 'package:flutter/foundation.dart' show kIsWeb;
import 'package:flutter_quill/flutter_quill.dart' as fq;
import 'package:meta/meta.dart' show immutable;
import 'embeds/image/editor/image_embed.dart';
import 'embeds/image/editor/image_web_embed.dart';
import 'embeds/image/toolbar/image_button.dart';
import 'embeds/others/camera_button/camera_button.dart';
import 'embeds/table/editor/table_embed.dart';
import 'embeds/table/toolbar/table_button.dart';
import 'embeds/video/editor/video_embed.dart';
import 'embeds/video/editor/video_web_embed.dart';
import 'embeds/video/toolbar/video_button.dart';
import 'models/config/camera/camera_configurations.dart';
import 'models/config/image/editor/image_configurations.dart';
import 'models/config/image/toolbar/image_configurations.dart';
import 'models/config/media/media_button_configurations.dart';
import 'models/config/table/table_configurations.dart';
import 'models/config/video/editor/video_configurations.dart';
import 'models/config/video/editor/video_web_configurations.dart';
import 'models/config/video/toolbar/video_configurations.dart';
import 'editor/image/image_embed.dart';
import 'editor/image/models/image_configurations.dart';
import 'editor/table/table_embed.dart';
import 'editor/video/models/video_configurations.dart';
import 'editor/video/models/video_web_configurations.dart';
import 'editor/video/video_embed.dart';
import 'editor/video/video_web_embed.dart';
import 'toolbar/camera/camera_button.dart';
import 'toolbar/camera/models/camera_configurations.dart';
import 'toolbar/image/image_button.dart';
import 'toolbar/image/models/image_configurations.dart';
import 'toolbar/table/models/table_configurations.dart';
import 'toolbar/table/table_button.dart';
import 'toolbar/video/models/video_configurations.dart';
import 'toolbar/video/video_button.dart';
@immutable
class FlutterQuillEmbeds {
@ -122,10 +120,6 @@ class FlutterQuillEmbeds {
const QuillToolbarVideoButtonOptions(),
QuillToolbarCameraButtonOptions? cameraButtonOptions,
QuillToolbarTableButtonOptions? tableButtonOptions,
@Deprecated(
'Media button has been removed, the value of this parameter will be ignored',
)
QuillToolbarMediaButtonOptions? mediaButtonOptions,
}) =>
[
if (imageButtonOptions != null)

@ -10,10 +10,10 @@ import 'package:flutter_quill/flutter_quill.dart'
kDefaultIconButtonFactor;
import 'package:flutter_quill/translations.dart';
import '../../../models/config/camera/camera_configurations.dart';
import '../../../models/config/shared_configurations.dart';
import '../../../services/image_picker/image_options.dart';
import '../../editor_toolbar_shared/image_picker/image_options.dart';
import '../../editor_toolbar_shared/shared_configurations.dart';
import 'camera_types.dart';
import 'models/camera_configurations.dart';
import 'select_camera_action.dart';
class QuillToolbarCameraButton extends StatelessWidget {

@ -1,8 +1,8 @@
import 'package:flutter/widgets.dart' show BuildContext;
import 'package:meta/meta.dart' show immutable;
import '../../image/editor/image_embed_types.dart';
import '../../video/video.dart';
import '../../editor/image/image_embed_types.dart';
import '../video/models/video.dart';
enum CameraAction {
video,

@ -1,6 +1,6 @@
import 'package:flutter_quill/flutter_quill.dart';
import '../../../embeds/others/camera_button/camera_types.dart';
import '../camera_types.dart';
class QuillToolbarCameraButtonExtraOptions
extends QuillToolbarBaseButtonExtraOptions {

@ -1,7 +1,7 @@
import 'package:flutter/material.dart';
import 'package:flutter_quill/flutter_quill.dart';
import '../../../models/config/formula/formula_configurations.dart';
import 'models/formula_configurations.dart';
class QuillToolbarFormulaButton extends StatelessWidget {
const QuillToolbarFormulaButton({

@ -4,11 +4,11 @@ import 'package:flutter/material.dart';
import 'package:flutter_quill/flutter_quill.dart';
import 'package:flutter_quill/translations.dart';
import '../../../models/config/image/toolbar/image_configurations.dart';
import '../../../models/config/shared_configurations.dart';
import '../../../services/image_picker/image_picker.dart';
import '../../others/image_video_utils.dart';
import '../editor/image_embed_types.dart';
import '../../common/image_video_utils.dart';
import '../../editor/image/image_embed_types.dart';
import '../../editor_toolbar_shared/image_picker/image_picker.dart';
import '../../editor_toolbar_shared/shared_configurations.dart';
import 'models/image_configurations.dart';
import 'select_image_source.dart';
class QuillToolbarImageButton extends StatelessWidget {

@ -1,7 +1,7 @@
import 'package:flutter_quill/flutter_quill.dart';
import 'package:meta/meta.dart' show immutable;
import '../../../../embeds/image/editor/image_embed_types.dart';
import '../../../editor/image/image_embed_types.dart';
class QuillToolbarImageButtonExtraOptions
extends QuillToolbarBaseButtonExtraOptions {

@ -2,7 +2,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_quill/extensions.dart' show isDesktop;
import 'package:flutter_quill/translations.dart';
import '../editor/image_embed_types.dart';
import '../../editor/image/image_embed_types.dart';
class SelectImageSourceDialog extends StatelessWidget {
const SelectImageSourceDialog({super.key});

@ -1,8 +1,9 @@
import 'package:flutter/material.dart';
import 'package:flutter_quill/flutter_quill.dart';
import 'package:flutter_quill/translations.dart';
import '../../../models/config/table/table_configurations.dart';
import '../../../utils/quill_table_utils.dart';
import '../../common/utils/quill_table_utils.dart';
import 'models/table_configurations.dart';
class QuillToolbarTableButton extends StatelessWidget {
const QuillToolbarTableButton({

@ -2,8 +2,8 @@ import 'package:flutter/widgets.dart' show BuildContext;
import 'package:flutter_quill/flutter_quill.dart';
import 'package:meta/meta.dart' show immutable;
import '../../extensions/controller_ext.dart';
import '../../services/image_picker/s_image_picker.dart';
import '../../../common/extensions/controller_ext.dart';
import '../../../editor_toolbar_shared/image_picker/s_image_picker.dart';
/// When request picking an video, for example when the video button toolbar
/// clicked, it should be null in case the user didn't choose any video or

@ -1,6 +1,6 @@
import 'package:flutter_quill/flutter_quill.dart';
import '../../../../embeds/video/video.dart';
import 'video.dart';
class QuillToolbarVideoButtonExtraOptions
extends QuillToolbarBaseButtonExtraOptions {

@ -2,7 +2,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_quill/extensions.dart' show isDesktop;
import 'package:flutter_quill/translations.dart';
import '../video.dart';
import 'models/video.dart';
class SelectVideoSourceDialog extends StatelessWidget {
const SelectVideoSourceDialog({super.key});

@ -2,11 +2,11 @@ import 'package:flutter/material.dart';
import 'package:flutter_quill/flutter_quill.dart';
import 'package:flutter_quill/translations.dart';
import '../../../models/config/shared_configurations.dart';
import '../../../models/config/video/toolbar/video_configurations.dart';
import '../../../services/image_picker/image_options.dart';
import '../../others/image_video_utils.dart';
import '../video.dart';
import '../../common/image_video_utils.dart';
import '../../editor_toolbar_shared/image_picker/image_options.dart';
import '../../editor_toolbar_shared/shared_configurations.dart';
import 'models/video.dart';
import 'models/video_configurations.dart';
import 'select_video_source.dart';
// TODO: Add custom callback to validate the video link input
Loading…
Cancel
Save