diff --git a/CHANGELOG.md b/CHANGELOG.md index 2c5a11f1b..20d91396a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +# [7.4.12] +- Update the minimum version of device_info_plus to 9.1.0 +- # [7.4.11] - Add sw locale. diff --git a/example/lib/pages/home_page.dart b/example/lib/pages/home_page.dart index 4e08e5be5..1f764cbce 100644 --- a/example/lib/pages/home_page.dart +++ b/example/lib/pages/home_page.dart @@ -1,6 +1,6 @@ import 'dart:async'; import 'dart:convert'; -import 'dart:io'; +import 'dart:io' show File, Platform; import 'dart:ui'; import 'package:file_picker/file_picker.dart'; diff --git a/example/lib/universal_ui/real_ui.dart b/example/lib/universal_ui/real_ui.dart index b701caf4d..6c1072fc7 100644 --- a/example/lib/universal_ui/real_ui.dart +++ b/example/lib/universal_ui/real_ui.dart @@ -1,4 +1,4 @@ -import 'dart:ui' as ui; +import 'dart:ui' if (dart.library.html) 'dart:ui_web' as ui; class PlatformViewRegistry { static void registerViewFactory(String viewId, dynamic cb) { diff --git a/example/lib/widgets/demo_scaffold.dart b/example/lib/widgets/demo_scaffold.dart index 0b14663cf..93d38663c 100644 --- a/example/lib/widgets/demo_scaffold.dart +++ b/example/lib/widgets/demo_scaffold.dart @@ -1,5 +1,5 @@ import 'dart:convert'; -import 'dart:io'; +import 'dart:io' show Platform; import 'package:filesystem_picker/filesystem_picker.dart'; import 'package:flutter/foundation.dart'; diff --git a/example/macos/Flutter/GeneratedPluginRegistrant.swift b/example/macos/Flutter/GeneratedPluginRegistrant.swift index 8a76d078d..9245196cc 100644 --- a/example/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/example/macos/Flutter/GeneratedPluginRegistrant.swift @@ -11,6 +11,7 @@ import gal import pasteboard import path_provider_foundation import url_launcher_macos +import video_player_avfoundation func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin")) @@ -19,4 +20,5 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { PasteboardPlugin.register(with: registry.registrar(forPlugin: "PasteboardPlugin")) PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin")) + FVPVideoPlayerPlugin.register(with: registry.registrar(forPlugin: "FVPVideoPlayerPlugin")) } diff --git a/flutter_quill_extensions/CHANGELOG.md b/flutter_quill_extensions/CHANGELOG.md index 19db1f351..f8a309ece 100644 --- a/flutter_quill_extensions/CHANGELOG.md +++ b/flutter_quill_extensions/CHANGELOG.md @@ -1,3 +1,9 @@ +## 0.5.1 +- Fix warrning "The platformViewRegistry getter is deprecated and will be removed in a future release. Please import it from dart:ui_web instead." +- Add QuillImageUtilities class +- Small improvemenets +- Allow to use the mobile context menu on desktop by force using it + ## 0.5.0 - Migrated from `gallery_saver` to `gal` for saving images - Added callbacks for greater control of editing images diff --git a/flutter_quill_extensions/lib/embeds/builders.dart b/flutter_quill_extensions/lib/embeds/builders.dart index e104674cc..e9f8d753c 100644 --- a/flutter_quill_extensions/lib/embeds/builders.dart +++ b/flutter_quill_extensions/lib/embeds/builders.dart @@ -20,13 +20,14 @@ import 'widgets/video_app.dart'; import 'widgets/youtube_video_app.dart'; class ImageEmbedBuilder extends EmbedBuilder { - const ImageEmbedBuilder({ + ImageEmbedBuilder({ this.onImageRemovedCallback, this.shouldRemoveImageCallback, + this.forceUseMobileOptionMenu = false, }); - final ImageEmbedBuilderOnRemovedCallback? onImageRemovedCallback; final ImageEmbedBuilderWillRemoveCallback? shouldRemoveImageCallback; + final bool forceUseMobileOptionMenu; @override String get key => BlockEmbed.imageType; @@ -79,7 +80,7 @@ class ImageEmbedBuilder extends EmbedBuilder { imageSize = OptionalSize((image as Image).width, image.height); } - if (!readOnly && base.isMobile()) { + if (!readOnly && (base.isMobile() || forceUseMobileOptionMenu)) { return GestureDetector( onTap: () { showDialog( @@ -152,7 +153,6 @@ class ImageEmbedBuilder extends EmbedBuilder { '', TextSelection.collapsed(offset: offset), ); - // Call the post remove callback if set await onImageRemovedCallback?.call(imageFile); }, @@ -162,7 +162,11 @@ class ImageEmbedBuilder extends EmbedBuilder { child: SimpleDialog( shape: const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(10))), - children: [resizeOption, copyOption, removeOption]), + children: [ + if (base.isMobile()) resizeOption, + copyOption, + removeOption, + ]), ); }); }, @@ -170,7 +174,16 @@ class ImageEmbedBuilder extends EmbedBuilder { ); } - if (!readOnly || !base.isMobile() || isImageBase64(imageUrl)) { + if (!readOnly || isImageBase64(imageUrl)) { + // To enforce using it on the web, desktop and other platforms + // and that is up to the developer + if (!base.isMobile() && forceUseMobileOptionMenu) { + return _menuOptionsForReadonlyImage( + context, + imageUrl, + image, + ); + } return image; } @@ -239,7 +252,7 @@ class VideoEmbedBuilder extends EmbedBuilder { assert(!kIsWeb, 'Please provide video EmbedBuilder for Web'); final videoUrl = node.value.data; - if (videoUrl.contains('youtube.com') || videoUrl.contains('youtu.be')) { + if (isYouTubeUrl(videoUrl)) { return YoutubeVideoApp( videoUrl: videoUrl, context: context, readOnly: readOnly); } diff --git a/flutter_quill_extensions/lib/embeds/embed_types.dart b/flutter_quill_extensions/lib/embeds/embed_types.dart index 1ce9d0e2f..46cc15637 100644 --- a/flutter_quill_extensions/lib/embeds/embed_types.dart +++ b/flutter_quill_extensions/lib/embeds/embed_types.dart @@ -1,4 +1,4 @@ -import 'dart:io'; +import 'dart:io' show File; import 'dart:typed_data'; import 'package:flutter/material.dart'; diff --git a/flutter_quill_extensions/lib/embeds/toolbar/image_video_utils.dart b/flutter_quill_extensions/lib/embeds/toolbar/image_video_utils.dart index 497822ae2..beb68ce39 100644 --- a/flutter_quill_extensions/lib/embeds/toolbar/image_video_utils.dart +++ b/flutter_quill_extensions/lib/embeds/toolbar/image_video_utils.dart @@ -1,4 +1,4 @@ -import 'dart:io'; +import 'dart:io' show File; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; diff --git a/flutter_quill_extensions/lib/embeds/toolbar/media_button.dart b/flutter_quill_extensions/lib/embeds/toolbar/media_button.dart index 837ca8253..2eaeec60d 100644 --- a/flutter_quill_extensions/lib/embeds/toolbar/media_button.dart +++ b/flutter_quill_extensions/lib/embeds/toolbar/media_button.dart @@ -1,4 +1,3 @@ -//import 'dart:io'; import 'dart:math' as math; import 'dart:ui'; diff --git a/flutter_quill_extensions/lib/embeds/utils.dart b/flutter_quill_extensions/lib/embeds/utils.dart index a2be5b98f..aea72e157 100644 --- a/flutter_quill_extensions/lib/embeds/utils.dart +++ b/flutter_quill_extensions/lib/embeds/utils.dart @@ -1,4 +1,4 @@ -import 'dart:io'; +import 'dart:io' show File; import 'package:flutter/foundation.dart' show Uint8List; import 'package:gal/gal.dart'; @@ -15,8 +15,28 @@ bool isBase64(String str) { return _base64.hasMatch(str); } +bool isHttpBasedUrl(String url) { + try { + final uri = Uri.parse(url.trim()); + return uri.isScheme('HTTP') || uri.isScheme('HTTPS'); + } catch (_) { + return false; + } +} + +bool isYouTubeUrl(String videoUrl) { + try { + final uri = Uri.parse(videoUrl); + return uri.host == 'www.youtube.com' || + uri.host == 'youtube.com' || + uri.host == 'youtu.be'; + } catch (_) { + return false; + } +} + bool isImageBase64(String imageUrl) { - return !imageUrl.startsWith('http') && isBase64(imageUrl); + return !isHttpBasedUrl(imageUrl) && isBase64(imageUrl); } enum SaveImageResultMethod { network, localStorage } diff --git a/flutter_quill_extensions/lib/embeds/widgets/image.dart b/flutter_quill_extensions/lib/embeds/widgets/image.dart index 658c50500..2679dac53 100644 --- a/flutter_quill_extensions/lib/embeds/widgets/image.dart +++ b/flutter_quill_extensions/lib/embeds/widgets/image.dart @@ -1,5 +1,5 @@ import 'dart:convert'; -import 'dart:io' as io; +import 'dart:io' show File; import 'package:flutter/material.dart'; import 'package:flutter_quill/flutter_quill.dart'; @@ -40,7 +40,7 @@ Image imageByUrl(String imageUrl, return Image.network(imageUrl, width: width, height: height, alignment: alignment); } - return Image.file(io.File(imageUrl), + return Image.file(File(imageUrl), width: width, height: height, alignment: alignment); } @@ -82,7 +82,7 @@ class ImageTapWrapper extends StatelessWidget { return NetworkImage(imageUrl); } - return FileImage(io.File(imageUrl)); + return FileImage(File(imageUrl)); } @override diff --git a/flutter_quill_extensions/lib/embeds/widgets/video_app.dart b/flutter_quill_extensions/lib/embeds/widgets/video_app.dart index eb0ba0f74..7ca9cb6bd 100644 --- a/flutter_quill_extensions/lib/embeds/widgets/video_app.dart +++ b/flutter_quill_extensions/lib/embeds/widgets/video_app.dart @@ -1,4 +1,4 @@ -import 'dart:io'; +import 'dart:io' show File; import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; diff --git a/flutter_quill_extensions/lib/flutter_quill_extensions.dart b/flutter_quill_extensions/lib/flutter_quill_extensions.dart index a443bcb01..afb49ccec 100644 --- a/flutter_quill_extensions/lib/flutter_quill_extensions.dart +++ b/flutter_quill_extensions/lib/flutter_quill_extensions.dart @@ -1,6 +1,7 @@ library flutter_quill_extensions; import 'package:flutter/material.dart'; +import 'package:flutter_quill/extensions.dart'; import 'package:flutter_quill/flutter_quill.dart'; import 'embeds/builders.dart'; @@ -22,29 +23,41 @@ export 'embeds/utils.dart'; class FlutterQuillEmbeds { /// Returns a list of embed builders for QuillEditor. /// + /// This method provides a collection of embed builders to enhance the + /// functionality + /// of a QuillEditor. It offers customization options for + /// handling various types of + /// embedded content, such as images, videos, and formulas. + /// /// **Note:** This method is not intended for web usage. - /// For web-specific embeds, use [webBuilders]. + /// For web-specific embeds, + /// use [webBuilders]. /// - /// [onVideoInit] is called when a video is initialized. + /// [onVideoInit] is a callback function that gets triggered when + /// a video is initialized. + /// You can use this to perform actions or setup configurations related + /// to video embedding. /// - /// [onImageRemovedCallback] is called when an image - /// is removed from the editor. This can be used to - /// delete the image from storage, for example: + /// [onImageRemovedCallback] is called when an image is + /// removed from the editor. + /// By default, [onImageRemovedCallback] deletes the + /// temporary image file if + /// the platform is mobile and if it still exists. You + /// can customize this behavior + /// by passing your own function that handles the removal process. /// + /// Example of [onImageRemovedCallback] customization: /// ```dart - /// (imageFile) async { - /// final fileExists = await imageFile.exists(); - /// if (fileExists) { - /// await imageFile.delete(); - /// } - /// }, + /// afterRemoveImageFromEditor: (imageFile) async { + /// // Your custom logic here + /// // or leave it empty to do nothing + /// } /// ``` /// - /// [shouldRemoveImageCallback] is called when the user - /// attempts to remove an image - /// from the editor. It allows you to control whether the image - /// should be removed - /// based on your custom logic. + /// [shouldRemoveImageCallback] is a callback + /// function that is invoked when the + /// user attempts to remove an image from the editor. It allows you to control + /// whether the image should be removed based on your custom logic. /// /// Example of [shouldRemoveImageCallback] customization: /// ```dart @@ -54,8 +67,8 @@ class FlutterQuillEmbeds { /// context: context, /// options: const YesOrCancelDialogOptions( /// title: 'Deleting an image', - /// message: 'Are you sure you want to delete this image - /// from the editor?', + /// message: 'Are you sure you want' ' to delete this + /// image from the editor?', /// ), /// ); /// @@ -63,14 +76,70 @@ class FlutterQuillEmbeds { /// return isShouldRemove; /// } /// ``` + /// + /// [forceUseMobileOptionMenuForImageClick] is a boolean + /// flag that, when set to `true`, + /// enforces the use of the mobile-specific option menu for image clicks in + /// other platforms like desktop, this option doesn't affect mobile. it will + /// not affect web + /// This option + /// can be used to override the default behavior based on the platform. + /// + /// The method returns a list of [EmbedBuilder] objects that can be used with + /// QuillEditor + /// to enable embedded content features like images, videos, and formulas. + /// + /// Example usage: + /// ```dart + /// final embedBuilders = QuillEmbedBuilders.builders( + /// onVideoInit: (videoContainerKey) { + /// // Custom video initialization logic + /// }, + /// // Customize other callback functions as needed + /// ); + /// + /// final quillEditor = QuillEditor( + /// // Other editor configurations + /// embedBuilders: embedBuilders, + /// ); + /// ``` static List builders({ void Function(GlobalKey videoContainerKey)? onVideoInit, ImageEmbedBuilderOnRemovedCallback? onImageRemovedCallback, ImageEmbedBuilderWillRemoveCallback? shouldRemoveImageCallback, + bool forceUseMobileOptionMenuForImageClick = false, }) => [ ImageEmbedBuilder( - onImageRemovedCallback: onImageRemovedCallback, + forceUseMobileOptionMenu: forceUseMobileOptionMenuForImageClick, + onImageRemovedCallback: onImageRemovedCallback ?? + (imageFile) async { + final mobile = isMobile(); + // If the platform is not mobile, return void; + // Since the mobile OS gives us a copy of the image + + // Note: We should remove the image on Flutter web + // since the behavior is similar to how it is on mobile, + // but since this builder is not for web, we will ignore it + if (!mobile) { + return; + } + + // On mobile OS (Android, iOS), the system will not give us + // direct access to the image; instead, + // it will give us the image + // in the temp directory of the application. So, we want to + // remove it when we no longer need it. + + // but on desktop we don't want to touch user files + // especially on macOS, where we can't even delete it without + // permission + + final isFileExists = await imageFile.exists(); + if (isFileExists) { + await imageFile.delete(); + } + }, shouldRemoveImageCallback: shouldRemoveImageCallback, ), VideoEmbedBuilder(onVideoInit: onVideoInit), diff --git a/flutter_quill_extensions/lib/shims/dart_ui_real.dart b/flutter_quill_extensions/lib/shims/dart_ui_real.dart index 69c06ee29..e38110eb7 100644 --- a/flutter_quill_extensions/lib/shims/dart_ui_real.dart +++ b/flutter_quill_extensions/lib/shims/dart_ui_real.dart @@ -1 +1 @@ -export 'dart:ui'; +export 'dart:ui' if (dart.library.html) 'dart:ui_web'; diff --git a/flutter_quill_extensions/lib/utils/quill_utils.dart b/flutter_quill_extensions/lib/utils/quill_utils.dart new file mode 100644 index 000000000..83096b283 --- /dev/null +++ b/flutter_quill_extensions/lib/utils/quill_utils.dart @@ -0,0 +1,276 @@ +import 'dart:io' show Directory, File, Platform; + +import 'package:flutter/foundation.dart' show kIsWeb; +import 'package:flutter_quill/flutter_quill.dart' as quill; +import 'package:path/path.dart' as path; + +import '../flutter_quill_extensions.dart'; + +class QuillImageUtilities { + const QuillImageUtilities._(); + + static void _webIsNotSupported(String functionName) { + if (kIsWeb) { + throw UnsupportedError( + 'The static function "$functionName()"' + ' on class "QuillImageUtilities" is not supported in Web', + ); + } + } + + /// Saves a list of images to a specified directory. + /// + /// This function is designed to work efficiently on + /// mobile platforms, but it can also be used on other platforms. + /// But it's not supported on web for now + /// + /// When you have a list of cached image paths + /// from a Quill document and you want to save them, + /// you can use this function. + /// It takes a list of image paths and copies each image to the specified + /// directory. If the image + /// path does not exist, it returns an + /// empty string for that item. + /// + /// Make sure that the image paths provided in the [images] + /// list exist, and handle the cases where images are not found accordingly. + /// + /// [images]: List of image paths to be saved. + /// [deleteThePreviousImages]: Indicates whether to delete the + /// original cached images after copying. + /// [saveDirectory]: The directory where the images will be saved. + /// [startOfEachFile]: Each file will have a name and it need to be unique + /// but to make the file name is clear we will need a string represent + /// the start of each file + /// + /// Returns a list of paths to the newly saved images. + /// For images that do not exist, their paths are returned as empty strings. + /// + /// Example usage: + /// ```dart + /// final documentsDir = await getApplicationDocumentsDirectory(); + /// final savedImagePaths = await saveImagesToDirectory( + /// images: cachedImagePaths, + /// deleteThePreviousImages: true, + /// saveDirectory: documentsDir, + /// startOfEachFile: 'quill-image-', // default + /// ); + /// ``` + static Future> saveImagesToDirectory({ + required Iterable images, + required deleteThePreviousImages, + required Directory saveDirectory, + String startOfEachFile = 'quill-image-', + }) async { + _webIsNotSupported('saveImagesToDirectory'); + final newImagesFutures = images.map((cachedImagePath) async { + final previousImageFile = File(cachedImagePath); + final isPreviousImageFileExists = await previousImageFile.exists(); + + if (!isPreviousImageFileExists) { + return ''; + } + + final newImageFileExtensionWithDot = path.extension(cachedImagePath); + + final dateTimeAsString = DateTime.now().toIso8601String(); + // TODO: You might want to make it easier for the developer to change + // the newImageFileName, but he can rename it anyway + final newImageFileName = + '$startOfEachFile$dateTimeAsString$newImageFileExtensionWithDot'; + final newImagePath = path.join(saveDirectory.path, newImageFileName); + final newImageFile = await previousImageFile.copy(newImagePath); + if (deleteThePreviousImages) { + await previousImageFile.delete(); + } + return newImageFile.path; + }); + // Await for the saving process for each image + final newImages = await Future.wait(newImagesFutures); + return newImages; + } + + /// Deletes all local images referenced in a Quill document. + /// it's not supported on web for now + /// + /// This function removes local images from the + /// file system that are referenced in the provided [document]. + /// + /// [document]: The Quill document from which images will be deleted. + /// + /// Throws an [Exception] if any errors occur during the deletion process. + /// + /// Example usage: + /// ```dart + /// try { + /// await deleteAllLocalImagesOfDocument(myQuillDocument); + /// } catch (e) { + /// print('Error deleting local images: $e'); + /// } + /// ``` + static Future deleteAllLocalImagesOfDocument( + quill.Document document, + ) async { + _webIsNotSupported('deleteAllLocalImagesOfDocument'); + final imagesPaths = getImagesPathsFromDocument( + document, + onlyLocalImages: true, + ); + for (final image in imagesPaths) { + final imageFile = File(image); + final fileExists = await imageFile.exists(); + if (!fileExists) { + return; + } + final deletedFile = await imageFile.delete(); + final deletedFileStillExists = await deletedFile.exists(); + if (deletedFileStillExists) { + throw Exception( + 'We have successfully deleted the file and it is still exists!!', + ); + } + } + } + + /// Retrieves paths to images embedded in a Quill document. + /// + /// it's not supported on web for now. + /// This function parses the [document] and returns a list of image paths. + /// + /// [document]: The Quill document from which image paths will be retrieved. + /// [onlyLocalImages]: If `true`, + /// only local (non-web-url) image paths will be included. + /// + /// Returns an iterable of image paths. + /// + /// Example usage: + /// ```dart + /// final quillDocument = _controller.document; + /// final imagePaths + /// = getImagesPathsFromDocument(quillDocument, onlyLocalImages: true); + /// print('Image paths: $imagePaths'); + /// ``` + /// + /// Note: This function assumes that images are + /// embedded as block embeds in the Quill document. + static Iterable getImagesPathsFromDocument( + quill.Document document, { + required bool onlyLocalImages, + }) { + _webIsNotSupported('getImagesPathsFromDocument'); + final images = document.root.children + .whereType() + .where((node) { + if (node.isEmpty) { + return false; + } + final firstNode = node.children.first; + if (firstNode is! quill.Embed) { + return false; + } + + if (firstNode.value.type != quill.BlockEmbed.imageType) { + return false; + } + final imageSource = firstNode.value.data; + if (imageSource is! String) { + return false; + } + if (onlyLocalImages && isHttpBasedUrl(imageSource)) { + return false; + } + return imageSource.trim().isNotEmpty; + }) + .toList() + .map((e) => (e.children.first as quill.Embed).value.data as String); + return images; + } + + /// Determines if an image file is cached based on the platform. + /// it's not supported on web for now + /// + /// On mobile platforms (Android and iOS), images are typically + /// cached in temporary directories. + /// This function helps identify whether the given image file path + /// is a cached path on supported platforms. + /// + /// [imagePath] is the path of the image file to check for caching. + /// + /// Returns `true` if the image is cached, `false` otherwise. + /// On other platforms it will always return false + static bool isImageCached(String imagePath) { + _webIsNotSupported('isImageCached'); + // Determine if the image path is a cached path based on platform + if (kIsWeb) { + // For now this will not work for web + return false; + } + if (Platform.isAndroid) { + return imagePath.contains('cache'); + } + if (Platform.isIOS) { + // Don't use isAppleOS() since macOS has different behavior + return imagePath.contains('tmp'); + } + // On other platforms like desktop + // The image is not cached and we will get a direct + // access to the image + return false; + } + + /// Retrieves cached image paths from a Quill document, + /// primarily for mobile platforms. + /// + /// it's not supported on web for now + /// + /// This function scans a Quill document to identify + /// and return paths to locally cached images. + /// It is specifically designed for mobile + /// operating systems (Android and iOS). + /// + /// [document] is the Quill document from which to extract image paths. + /// + /// [replaceUnexistentImagesWith] is an optional parameter. + /// If provided, it replaces non-existent image paths + /// with the specified value. If not provided, non-existent + /// image paths are removed from the result. + /// + /// Returns a list of cached image paths found in the document. + /// On non-mobile platforms, this function returns an empty list. + static Future> getCachedImagePathsFromDocument( + quill.Document document, { + String? replaceUnexistentImagesWith, + }) async { + _webIsNotSupported('getCachedImagePathsFromDocument'); + final imagePaths = getImagesPathsFromDocument( + document, + onlyLocalImages: true, + ); + + // We don't want the not cached images to be saved again for example. + final cachesImagePaths = imagePaths.where((imagePath) { + final isCurrentImageCached = isImageCached(imagePath); + return isCurrentImageCached; + }).toList(); + + // Remove all the images that doesn't exists + for (final imagePath in cachesImagePaths) { + final file = File(imagePath); + final exists = await file.exists(); + if (!exists) { + final index = cachesImagePaths.indexOf(imagePath); + if (index == -1) { + continue; + } + cachesImagePaths.removeAt(index); + if (replaceUnexistentImagesWith != null) { + cachesImagePaths.insert( + index, + replaceUnexistentImagesWith, + ); + } + } + } + return cachesImagePaths; + } +} diff --git a/flutter_quill_extensions/pubspec.yaml b/flutter_quill_extensions/pubspec.yaml index c3019116c..206cc0c7b 100644 --- a/flutter_quill_extensions/pubspec.yaml +++ b/flutter_quill_extensions/pubspec.yaml @@ -1,6 +1,6 @@ name: flutter_quill_extensions description: Embed extensions for flutter_quill including image, video, formula and etc. -version: 0.5.0 +version: 0.5.1 homepage: https://bulletjournal.us/home/index.html repository: https://github.com/singerdmx/flutter-quill/tree/master/flutter_quill_extensions @@ -12,17 +12,17 @@ dependencies: flutter: sdk: flutter - flutter_quill: ^7.4.7 + flutter_quill: ^7.4.9 - gal: ^2.1.1 http: ^1.1.0 - image_picker: ">=0.8.5 <2.0.0" - math_keyboard: ">=0.1.8 <0.3.0" + image_picker: ">=1.0.4" photo_view: ^0.14.0 - universal_html: ^2.2.1 - url_launcher: ^6.1.9 - video_player: ^2.7.0 - youtube_player_flutter: ^8.1.1 + video_player: ^2.7.2 + youtube_player_flutter: ^8.1.2 + math_keyboard: ">=0.2.1" + universal_html: ^2.2.4 + + gal: ^2.1.2 dev_dependencies: flutter_test: diff --git a/pubspec.yaml b/pubspec.yaml index 9ce76f37b..27b331a8e 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -20,8 +20,8 @@ dependencies: characters: ^1.3.0 diff_match_patch: ^0.4.1 i18n_extension: ^9.0.2 - device_info_plus: ^9.0.3 - platform: ^3.1.2 + device_info_plus: ^9.1.0 + platform: ^3.1.3 pasteboard: ^0.2.0 # Dependencies for testing utilities