From b7224751c1c68d1e718aab9bf97004e6843a3926 Mon Sep 17 00:00:00 2001 From: Ahmed Hnewa <73608287+ahmedhnewa@users.noreply.github.com> Date: Sat, 30 Sep 2023 02:03:10 +0300 Subject: [PATCH 1/7] Code documentations and new event for confirm remove the image (#1414) * Add a event that triggers after removing the image from the editor && delete unused dependencies and upgrade all packages and plugins and remove gallery_saver which has not been updated for more than 23 months, it was a great plugin but it old now, and I also add some simple documentation and other minor improvements * I have add a documentation comments to flutter_quill_extensions, add new event to allow the user to confirm removing the image before actually remove it, translated some text in Arabic languague since it was incorrect or missing * Fix analyzer error --- .../Flutter/GeneratedPluginRegistrant.swift | 2 + .../lib/embeds/builders.dart | 27 +++-- .../lib/embeds/embed_types.dart | 8 +- .../lib/flutter_quill_extensions.dart | 105 ++++++++++++++++-- lib/src/translations/toolbar.i18n.dart | 8 +- pubspec.yaml | 4 +- 6 files changed, 132 insertions(+), 22 deletions(-) diff --git a/example/macos/Flutter/GeneratedPluginRegistrant.swift b/example/macos/Flutter/GeneratedPluginRegistrant.swift index 8a76d078..9245196c 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/lib/embeds/builders.dart b/flutter_quill_extensions/lib/embeds/builders.dart index e78b3e80..a8fdb470 100644 --- a/flutter_quill_extensions/lib/embeds/builders.dart +++ b/flutter_quill_extensions/lib/embeds/builders.dart @@ -21,8 +21,13 @@ import 'widgets/video_app.dart'; import 'widgets/youtube_video_app.dart'; class ImageEmbedBuilder extends EmbedBuilder { - ImageEmbedBuilder({required this.afterRemoveImageFromEditor}); + ImageEmbedBuilder({ + required this.afterRemoveImageFromEditor, + required this.shouldRemoveImageFromEditor, + }); final ImageEmbedBuilderAfterRemoveImageFromEditor afterRemoveImageFromEditor; + final ImageEmbedBuilderShouldRemoveImageFromEditor + shouldRemoveImageFromEditor; @override String get key => BlockEmbed.imageType; @@ -128,18 +133,26 @@ class ImageEmbedBuilder extends EmbedBuilder { color: Colors.red.shade200, text: 'Remove'.i18n, onPressed: () async { - final navigator = Navigator.of(context); - final offset = - getEmbedNode(controller, controller.selection.start) - .offset; + Navigator.of(context).pop(); + + final imageFile = File(imageUrl); + final shouldRemoveImage = + await shouldRemoveImageFromEditor(imageFile); + + if (!shouldRemoveImage) { + return; + } + final offset = getEmbedNode( + controller, + controller.selection.start, + ).offset; controller.replaceText( offset, 1, '', TextSelection.collapsed(offset: offset), ); - navigator.pop(); - await afterRemoveImageFromEditor(File(imageUrl)); + await afterRemoveImageFromEditor(imageFile); }, ); return Padding( diff --git a/flutter_quill_extensions/lib/embeds/embed_types.dart b/flutter_quill_extensions/lib/embeds/embed_types.dart index 8e54954e..a785fb70 100644 --- a/flutter_quill_extensions/lib/embeds/embed_types.dart +++ b/flutter_quill_extensions/lib/embeds/embed_types.dart @@ -46,4 +46,10 @@ class QuillFile { } typedef ImageEmbedBuilderAfterRemoveImageFromEditor = Future Function( - File imageFile); + File imageFile, +); + +typedef ImageEmbedBuilderShouldRemoveImageFromEditor = Future Function( + File imageFile, +); + diff --git a/flutter_quill_extensions/lib/flutter_quill_extensions.dart b/flutter_quill_extensions/lib/flutter_quill_extensions.dart index f2f56fb8..ecc3b949 100644 --- a/flutter_quill_extensions/lib/flutter_quill_extensions.dart +++ b/flutter_quill_extensions/lib/flutter_quill_extensions.dart @@ -20,44 +20,133 @@ export 'embeds/toolbar/video_button.dart'; export 'embeds/utils.dart'; class FlutterQuillEmbeds { - /// Returns a list of embed builders for Quill editors. + /// Returns a list of embed builders for QuillEditor. + /// + /// **Note:** This method is not intended for web usage. + /// For web-specific embeds, use [webBuilders]. /// /// [onVideoInit] is called when a video is initialized. - /// [onRemoveImage] is called when an image is removed from the editor. - /// By default, [onRemoveImage] deletes the cached image if it still exists. - /// If you want to customize - /// the behavior, pass your own function that handles the removal. /// - /// Example of [onRemoveImage] customization: + /// [afterRemoveImageFromEditor] is called when an image + /// is removed from the editor. + /// By default, [afterRemoveImageFromEditor] deletes the cached + /// image if it still exists. + /// If you want to customize the behavior, pass your own function + /// that handles the removal. + /// + /// Example of [afterRemoveImageFromEditor] customization: /// ```dart - /// onRemoveImage: (imageFile) async { + /// afterRemoveImageFromEditor: (imageFile) async { /// // Your custom logic here /// // or leave it empty to do nothing /// } /// ``` + /// + /// [shouldRemoveImageFromEditor] 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. + /// + /// Example of [shouldRemoveImageFromEditor] customization: + /// ```dart + /// shouldRemoveImageFromEditor: (imageFile) async { + /// // Show a confirmation dialog before removing the image + /// final isShouldRemove = await showYesCancelDialog( + /// context: context, + /// options: const YesOrCancelDialogOptions( + /// title: 'Deleting an image', + /// message: 'Are you sure you want to delete this image + /// from the editor?', + /// ), + /// ); + /// + /// // Return `true` to allow image removal if the user confirms, otherwise `false` + /// return isShouldRemove; + /// } + /// ``` static List builders({ void Function(GlobalKey videoContainerKey)? onVideoInit, ImageEmbedBuilderAfterRemoveImageFromEditor? afterRemoveImageFromEditor, + ImageEmbedBuilderShouldRemoveImageFromEditor? shouldRemoveImageFromEditor, }) => [ ImageEmbedBuilder( afterRemoveImageFromEditor: afterRemoveImageFromEditor ?? (imageFile) async { - // TODO: Please change this default code + // TODO: Change the default event if you want to final fileExists = await imageFile.exists(); if (fileExists) { await imageFile.delete(); } }, + shouldRemoveImageFromEditor: shouldRemoveImageFromEditor ?? + (imageFile) { + // TODO: Before pubish the changes + // please consider change the name + // of the events if you want to + return Future.value(true); + }, ), VideoEmbedBuilder(onVideoInit: onVideoInit), FormulaEmbedBuilder(), ]; + /// Returns a list of embed builders specifically designed for web support. + /// + /// [ImageEmbedBuilderWeb] is the embed builder for handling + /// images on the web. + /// static List webBuilders() => [ ImageEmbedBuilderWeb(), ]; + /// Returns a list of embed button builders to customize the toolbar buttons. + /// + /// [showImageButton] determines whether the image button should be displayed. + /// [showVideoButton] determines whether the video button should be displayed. + /// [showCameraButton] determines whether the camera button should + /// be displayed. + /// [showFormulaButton] determines whether the formula button + /// should be displayed. + /// + /// [imageButtonTooltip] specifies the tooltip text for the image button. + /// [videoButtonTooltip] specifies the tooltip text for the video button. + /// [cameraButtonTooltip] specifies the tooltip text for the camera button. + /// [formulaButtonTooltip] specifies the tooltip text for the formula button. + /// + /// [onImagePickCallback] is a callback function called when an + /// image is picked. + /// [onVideoPickCallback] is a callback function called when a + /// video is picked. + /// + /// [mediaPickSettingSelector] allows customizing media pick settings. + /// [cameraPickSettingSelector] allows customizing camera pick settings. + /// + /// Example of customizing media pick settings for the image button: + /// ```dart + /// mediaPickSettingSelector: (context) async { + /// final mediaPickSetting = await showModalBottomSheet( + /// showDragHandle: true, + /// context: context, + /// constraints: const BoxConstraints(maxWidth: 640), + /// builder: (context) => const SelectImageSourceDialog(), + /// ); + /// if (mediaPickSetting == null) { + /// return null; + /// } + /// return mediaPickSetting; + /// } + /// ``` + /// + /// [filePickImpl] is an implementation for picking files. + /// [webImagePickImpl] is an implementation for picking web images. + /// [webVideoPickImpl] is an implementation for picking web videos. + /// + /// [imageLinkRegExp] is a regular expression to identify image links. + /// [videoLinkRegExp] is a regular expression to identify video links. + /// + /// The returned list contains embed button builders for the Quill toolbar. static List buttons({ bool showImageButton = true, bool showVideoButton = true, diff --git a/lib/src/translations/toolbar.i18n.dart b/lib/src/translations/toolbar.i18n.dart index 149fb628..4eeb07fd 100644 --- a/lib/src/translations/toolbar.i18n.dart +++ b/lib/src/translations/toolbar.i18n.dart @@ -198,7 +198,7 @@ extension Localization on String { 'Align right': 'محاذاة اليمين', // i think it should be 'Justify with width' // it is wrong in all properties - 'Justify win width': 'Justify win width', + 'Justify win width': 'تبرير مع العرض', 'Text direction': 'اتجاه النص', 'Header style': 'ستايل العنوان', 'Numbered list': 'قائمة مرقمة', @@ -217,9 +217,9 @@ extension Localization on String { 'Hex': 'Hex', 'Material': 'Material', 'Color': 'اللون', - 'Find text': 'Find text', - 'Move to previous occurrence': 'Move to previous occurrence', - 'Move to next occurrence': 'Move to next occurrence', + 'Find text': 'بحث عن نص', + 'Move to previous occurrence': 'الانتقال إلى الحدث السابق', + 'Move to next occurrence': 'الانتقال إلى الحدث التالي', }, 'da': { 'Paste a link': 'Indsæt link', diff --git a/pubspec.yaml b/pubspec.yaml index 49f33228..3459911b 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -15,13 +15,13 @@ dependencies: flutter_colorpicker: ^1.0.3 flutter_keyboard_visibility: ^5.4.1 quiver: ^3.2.1 - url_launcher: ^6.1.12 + url_launcher: ^6.1.14 pedantic: ^1.11.1 characters: ^1.3.0 diff_match_patch: ^0.4.1 i18n_extension: ^9.0.2 device_info_plus: ^9.0.3 - platform: ^3.1.0 + platform: ^3.1.2 pasteboard: ^0.2.0 # Dependencies for testing utilities From 848a0b5d02d1d1fae35ae0c76890d464e3197a7b Mon Sep 17 00:00:00 2001 From: Cheryl Date: Sat, 30 Sep 2023 21:48:35 -0700 Subject: [PATCH 2/7] Upgrade to 7.4.8 --- CHANGELOG.md | 3 +++ pubspec.yaml | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 83c555c6..bd095115 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +# [7.4.8] +- Upgrade dependencies. + # [7.4.7] - Add Vietnamese and German translations. diff --git a/pubspec.yaml b/pubspec.yaml index 3459911b..a7d6d467 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: flutter_quill description: A rich text editor built for the modern Android, iOS, web and desktop platforms. It is the WYSIWYG editor and a Quill component for Flutter. -version: 7.4.7 +version: 7.4.8 homepage: https://1o24bbs.com/c/bulletjournal/108 repository: https://github.com/singerdmx/flutter-quill From 84c2437e23dc5f78cf72200c2e0d31fa86e96027 Mon Sep 17 00:00:00 2001 From: Alspb <73047043+Alspb@users.noreply.github.com> Date: Mon, 2 Oct 2023 01:23:54 +0100 Subject: [PATCH 3/7] Style recognition fixes (#1416) --- lib/src/models/documents/document.dart | 35 +++++++++++++++--------- lib/src/models/documents/nodes/line.dart | 13 +++------ 2 files changed, 26 insertions(+), 22 deletions(-) diff --git a/lib/src/models/documents/document.dart b/lib/src/models/documents/document.dart index 6266b42b..55617865 100644 --- a/lib/src/models/documents/document.dart +++ b/lib/src/models/documents/document.dart @@ -156,19 +156,28 @@ class Document { /// included in the result. Style collectStyle(int index, int len) { final res = queryChild(index); - // -1 because the cursor is at the part of the line that is not visible - // Bug: When the caret is in the middle of the paragraph - // and at the end of the format string, it will display the wrong state - // of the format button - final isLinkStyle = - res.node?.style.attributes[Attribute.link.key]?.value == true; - // In this case, we have an exception, this is a link. - // When node is a link we will not -1 - return (res.node as Line).collectStyle( - len == 0 && res.node != null && !isLinkStyle - ? res.offset - 1 - : res.offset, - len); + Style rangeStyle; + if (len > 0) { + return (res.node as Line).collectStyle(res.offset, len); + } + if (res.offset == 0) { + rangeStyle = (res.node as Line).collectStyle(res.offset, len); + return rangeStyle.removeAll({ + for (final attr in rangeStyle.values) + if (attr.isInline) attr + }); + } + rangeStyle = (res.node as Line).collectStyle(res.offset - 1, len); + final linkAttribute = rangeStyle.attributes[Attribute.link.key]; + if ((linkAttribute != null) && + (linkAttribute.value != + (res.node as Line) + .collectStyle(res.offset, len) + .attributes[Attribute.link.key] + ?.value)) { + return rangeStyle.removeAll({linkAttribute}); + } + return rangeStyle; } /// Returns all styles and Embed for each node within selection diff --git a/lib/src/models/documents/nodes/line.dart b/lib/src/models/documents/nodes/line.dart index b9e7191d..539f3c5d 100644 --- a/lib/src/models/documents/nodes/line.dart +++ b/lib/src/models/documents/nodes/line.dart @@ -352,18 +352,13 @@ class Line extends Container { final excluded = {}; void _handle(Style style) { - if (result.isEmpty) { - excluded.addAll(style.values); - } else { - for (final attr in result.values) { - if (!style.containsKey(attr.key)) { - excluded.add(attr); - } + for (final attr in result.values) { + if (!style.containsKey(attr.key) || + (style.attributes[attr.key] != attr.value)) { + excluded.add(attr); } } - final remaining = style.removeAll(excluded); result = result.removeAll(excluded); - result = result.mergeAll(remaining); } final data = queryChild(offset, true); From ff381e6e07230fdf555413ca92337ba766d8c1c3 Mon Sep 17 00:00:00 2001 From: Cheryl Date: Sun, 1 Oct 2023 17:41:34 -0700 Subject: [PATCH 4/7] Upgrade to 7.4.9 --- CHANGELOG.md | 3 +++ pubspec.yaml | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bd095115..2699e233 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +# [7.4.9] +- Style recognition fixes. + # [7.4.8] - Upgrade dependencies. diff --git a/pubspec.yaml b/pubspec.yaml index a7d6d467..c8fec16a 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: flutter_quill description: A rich text editor built for the modern Android, iOS, web and desktop platforms. It is the WYSIWYG editor and a Quill component for Flutter. -version: 7.4.8 +version: 7.4.9 homepage: https://1o24bbs.com/c/bulletjournal/108 repository: https://github.com/singerdmx/flutter-quill From 9fcd0a7e7aecdc6f116e96c1d4728253728d38a6 Mon Sep 17 00:00:00 2001 From: Ahmed Hnewa <73608287+ahmedhnewa@users.noreply.github.com> Date: Wed, 4 Oct 2023 21:33:22 +0300 Subject: [PATCH 5/7] Fix my issues and changes (#1417) * Add a event that triggers after removing the image from the editor && delete unused dependencies and upgrade all packages and plugins and remove gallery_saver which has not been updated for more than 23 months, it was a great plugin but it old now, and I also add some simple documentation and other minor improvements * I have add a documentation comments to flutter_quill_extensions, add new event to allow the user to confirm removing the image before actually remove it, translated some text in Arabic languague since it was incorrect or missing * Fix analyzer error * Switch back to gal and more changes * Remove required parameters --- .../lib/embeds/builders.dart | 27 ++++++++++++------- .../lib/embeds/utils.dart | 17 ++++++------ .../lib/flutter_quill_extensions.dart | 17 ++---------- flutter_quill_extensions/pubspec.yaml | 2 +- 4 files changed, 30 insertions(+), 33 deletions(-) diff --git a/flutter_quill_extensions/lib/embeds/builders.dart b/flutter_quill_extensions/lib/embeds/builders.dart index a8fdb470..58ad4ff8 100644 --- a/flutter_quill_extensions/lib/embeds/builders.dart +++ b/flutter_quill_extensions/lib/embeds/builders.dart @@ -11,8 +11,7 @@ import 'package:math_keyboard/math_keyboard.dart'; import 'package:universal_html/html.dart' as html; import '../shims/dart_ui_fake.dart' - if (dart.library.html) 'package:flutter_quill_extensions/shims/dart_ui_real.dart' - as ui; + if (dart.library.html) '../shims/dart_ui_real.dart' as ui; import 'embed_types.dart'; import 'utils.dart'; import 'widgets/image.dart'; @@ -22,11 +21,11 @@ import 'widgets/youtube_video_app.dart'; class ImageEmbedBuilder extends EmbedBuilder { ImageEmbedBuilder({ - required this.afterRemoveImageFromEditor, - required this.shouldRemoveImageFromEditor, + this.afterRemoveImageFromEditor, + this.shouldRemoveImageFromEditor, }); - final ImageEmbedBuilderAfterRemoveImageFromEditor afterRemoveImageFromEditor; - final ImageEmbedBuilderShouldRemoveImageFromEditor + final ImageEmbedBuilderAfterRemoveImageFromEditor? afterRemoveImageFromEditor; + final ImageEmbedBuilderShouldRemoveImageFromEditor? shouldRemoveImageFromEditor; @override @@ -136,8 +135,15 @@ class ImageEmbedBuilder extends EmbedBuilder { Navigator.of(context).pop(); final imageFile = File(imageUrl); - final shouldRemoveImage = - await shouldRemoveImageFromEditor(imageFile); + + final shouldRemoveImageEvent = shouldRemoveImageFromEditor; + + var shouldRemoveImage = true; + if (shouldRemoveImageEvent != null) { + shouldRemoveImage = await shouldRemoveImageEvent( + imageFile, + ); + } if (!shouldRemoveImage) { return; @@ -152,7 +158,10 @@ class ImageEmbedBuilder extends EmbedBuilder { '', TextSelection.collapsed(offset: offset), ); - await afterRemoveImageFromEditor(imageFile); + final afterRemoveImageEvent = afterRemoveImageFromEditor; + if (afterRemoveImageEvent != null) { + await afterRemoveImageEvent(imageFile); + } }, ); return Padding( diff --git a/flutter_quill_extensions/lib/embeds/utils.dart b/flutter_quill_extensions/lib/embeds/utils.dart index d4b937a3..a2be5b98 100644 --- a/flutter_quill_extensions/lib/embeds/utils.dart +++ b/flutter_quill_extensions/lib/embeds/utils.dart @@ -1,8 +1,8 @@ import 'dart:io'; import 'package:flutter/foundation.dart' show Uint8List; +import 'package:gal/gal.dart'; import 'package:http/http.dart' as http; -import 'package:image_gallery_saver/image_gallery_saver.dart'; // I would like to orgnize the project structure and the code more // but here I don't want to change too much since that is a community project @@ -30,7 +30,11 @@ class _SaveImageResult { Future<_SaveImageResult> saveImage(String imageUrl) async { final imageFile = File(imageUrl); + final hasPermission = await Gal.hasAccess(); final imageExistsLocally = await imageFile.exists(); + if (!hasPermission) { + await Gal.requestAccess(); + } if (!imageExistsLocally) { final success = await _saveNetworkImageToLocal(imageUrl); return _SaveImageResult( @@ -54,10 +58,8 @@ Future _saveNetworkImageToLocal(String imageUrl) async { return false; } final imageBytes = response.bodyBytes; - final result = await ImageGallerySaver.saveImage( - Uint8List.fromList(imageBytes), - ); - return result['isSuccess']; + await Gal.putImageBytes(imageBytes); + return true; } catch (e) { return false; } @@ -75,9 +77,8 @@ Future _convertFileToUint8List(File file) async { Future _saveImageLocally(File imageFile) async { try { final imageBytes = await _convertFileToUint8List(imageFile); - final result = await ImageGallerySaver.saveImage(imageBytes); - - return result['isSuccess']; + await Gal.putImageBytes(imageBytes); + return true; } catch (e) { return false; } diff --git a/flutter_quill_extensions/lib/flutter_quill_extensions.dart b/flutter_quill_extensions/lib/flutter_quill_extensions.dart index ecc3b949..2686581e 100644 --- a/flutter_quill_extensions/lib/flutter_quill_extensions.dart +++ b/flutter_quill_extensions/lib/flutter_quill_extensions.dart @@ -72,21 +72,8 @@ class FlutterQuillEmbeds { }) => [ ImageEmbedBuilder( - afterRemoveImageFromEditor: afterRemoveImageFromEditor ?? - (imageFile) async { - // TODO: Change the default event if you want to - final fileExists = await imageFile.exists(); - if (fileExists) { - await imageFile.delete(); - } - }, - shouldRemoveImageFromEditor: shouldRemoveImageFromEditor ?? - (imageFile) { - // TODO: Before pubish the changes - // please consider change the name - // of the events if you want to - return Future.value(true); - }, + afterRemoveImageFromEditor: afterRemoveImageFromEditor, + shouldRemoveImageFromEditor: shouldRemoveImageFromEditor, ), VideoEmbedBuilder(onVideoInit: onVideoInit), FormulaEmbedBuilder(), diff --git a/flutter_quill_extensions/pubspec.yaml b/flutter_quill_extensions/pubspec.yaml index 9216304d..c3efe10e 100644 --- a/flutter_quill_extensions/pubspec.yaml +++ b/flutter_quill_extensions/pubspec.yaml @@ -26,7 +26,7 @@ dependencies: # url_launcher: ^6.1.14 # dio: ^5.3.3 - image_gallery_saver: ^2.0.3 + gal: ^2.1.1 dev_dependencies: flutter_test: From 09f2778acba116cdc8b44de9256fe5dc2b936363 Mon Sep 17 00:00:00 2001 From: Jonathan Salmon Date: Wed, 4 Oct 2023 23:09:01 +0100 Subject: [PATCH 6/7] extensions: update docs and release package 0.5.0 --- .../Flutter/GeneratedPluginRegistrant.swift | 2 -- flutter_quill_extensions/CHANGELOG.md | 4 +++ .../lib/embeds/builders.dart | 33 +++++++----------- .../lib/embeds/embed_types.dart | 5 ++- .../lib/flutter_quill_extensions.dart | 34 +++++++++---------- flutter_quill_extensions/pubspec.yaml | 19 ++++------- 6 files changed, 42 insertions(+), 55 deletions(-) diff --git a/example/macos/Flutter/GeneratedPluginRegistrant.swift b/example/macos/Flutter/GeneratedPluginRegistrant.swift index 9245196c..8a76d078 100644 --- a/example/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/example/macos/Flutter/GeneratedPluginRegistrant.swift @@ -11,7 +11,6 @@ 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")) @@ -20,5 +19,4 @@ 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 82e52442..19db1f35 100644 --- a/flutter_quill_extensions/CHANGELOG.md +++ b/flutter_quill_extensions/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.5.0 +- Migrated from `gallery_saver` to `gal` for saving images +- Added callbacks for greater control of editing images + ## 0.4.1 - Updated dependencies to support image_picker 1.0 diff --git a/flutter_quill_extensions/lib/embeds/builders.dart b/flutter_quill_extensions/lib/embeds/builders.dart index 58ad4ff8..0e5e38ea 100644 --- a/flutter_quill_extensions/lib/embeds/builders.dart +++ b/flutter_quill_extensions/lib/embeds/builders.dart @@ -20,13 +20,13 @@ import 'widgets/video_app.dart'; import 'widgets/youtube_video_app.dart'; class ImageEmbedBuilder extends EmbedBuilder { - ImageEmbedBuilder({ - this.afterRemoveImageFromEditor, - this.shouldRemoveImageFromEditor, + const ImageEmbedBuilder({ + this.onImageRemovedCallback, + this.shouldRemoveImageCallback, }); - final ImageEmbedBuilderAfterRemoveImageFromEditor? afterRemoveImageFromEditor; - final ImageEmbedBuilderShouldRemoveImageFromEditor? - shouldRemoveImageFromEditor; + + final ImageEmbedBuilderOnRemovedCallback? onImageRemovedCallback; + final ImageEmbedBuilderWillRemoveCallback? shouldRemoveImageCallback; @override String get key => BlockEmbed.imageType; @@ -136,18 +136,12 @@ class ImageEmbedBuilder extends EmbedBuilder { final imageFile = File(imageUrl); - final shouldRemoveImageEvent = shouldRemoveImageFromEditor; - - var shouldRemoveImage = true; - if (shouldRemoveImageEvent != null) { - shouldRemoveImage = await shouldRemoveImageEvent( - imageFile, - ); - } - - if (!shouldRemoveImage) { + // Call the remove check callback if set + if (await shouldRemoveImageCallback?.call(imageFile) == + false) { return; } + final offset = getEmbedNode( controller, controller.selection.start, @@ -158,10 +152,9 @@ class ImageEmbedBuilder extends EmbedBuilder { '', TextSelection.collapsed(offset: offset), ); - final afterRemoveImageEvent = afterRemoveImageFromEditor; - if (afterRemoveImageEvent != null) { - await afterRemoveImageEvent(imageFile); - } + + // Call the post remove callback if set + await onImageRemovedCallback?.call(imageFile); }, ); return Padding( diff --git a/flutter_quill_extensions/lib/embeds/embed_types.dart b/flutter_quill_extensions/lib/embeds/embed_types.dart index a785fb70..1ce9d0e2 100644 --- a/flutter_quill_extensions/lib/embeds/embed_types.dart +++ b/flutter_quill_extensions/lib/embeds/embed_types.dart @@ -45,11 +45,10 @@ class QuillFile { final Uint8List bytes; } -typedef ImageEmbedBuilderAfterRemoveImageFromEditor = Future Function( +typedef ImageEmbedBuilderWillRemoveCallback = Future Function( File imageFile, ); -typedef ImageEmbedBuilderShouldRemoveImageFromEditor = Future Function( +typedef ImageEmbedBuilderOnRemovedCallback = Future Function( File imageFile, ); - diff --git a/flutter_quill_extensions/lib/flutter_quill_extensions.dart b/flutter_quill_extensions/lib/flutter_quill_extensions.dart index 2686581e..a443bcb0 100644 --- a/flutter_quill_extensions/lib/flutter_quill_extensions.dart +++ b/flutter_quill_extensions/lib/flutter_quill_extensions.dart @@ -27,28 +27,26 @@ class FlutterQuillEmbeds { /// /// [onVideoInit] is called when a video is initialized. /// - /// [afterRemoveImageFromEditor] is called when an image - /// is removed from the editor. - /// By default, [afterRemoveImageFromEditor] deletes the cached - /// image if it still exists. - /// If you want to customize the behavior, pass your own function - /// that handles the removal. - /// - /// Example of [afterRemoveImageFromEditor] customization: + /// [onImageRemovedCallback] is called when an image + /// is removed from the editor. This can be used to + /// delete the image from storage, for example: + /// /// ```dart - /// afterRemoveImageFromEditor: (imageFile) async { - /// // Your custom logic here - /// // or leave it empty to do nothing - /// } + /// (imageFile) async { + /// final fileExists = await imageFile.exists(); + /// if (fileExists) { + /// await imageFile.delete(); + /// } + /// }, /// ``` /// - /// [shouldRemoveImageFromEditor] is called when the user + /// [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. /// - /// Example of [shouldRemoveImageFromEditor] customization: + /// Example of [shouldRemoveImageCallback] customization: /// ```dart /// shouldRemoveImageFromEditor: (imageFile) async { /// // Show a confirmation dialog before removing the image @@ -67,13 +65,13 @@ class FlutterQuillEmbeds { /// ``` static List builders({ void Function(GlobalKey videoContainerKey)? onVideoInit, - ImageEmbedBuilderAfterRemoveImageFromEditor? afterRemoveImageFromEditor, - ImageEmbedBuilderShouldRemoveImageFromEditor? shouldRemoveImageFromEditor, + ImageEmbedBuilderOnRemovedCallback? onImageRemovedCallback, + ImageEmbedBuilderWillRemoveCallback? shouldRemoveImageCallback, }) => [ ImageEmbedBuilder( - afterRemoveImageFromEditor: afterRemoveImageFromEditor, - shouldRemoveImageFromEditor: shouldRemoveImageFromEditor, + onImageRemovedCallback: onImageRemovedCallback, + shouldRemoveImageCallback: shouldRemoveImageCallback, ), VideoEmbedBuilder(onVideoInit: onVideoInit), FormulaEmbedBuilder(), diff --git a/flutter_quill_extensions/pubspec.yaml b/flutter_quill_extensions/pubspec.yaml index c3efe10e..0ea3297a 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.4.1 +version: 0.5.0 homepage: https://bulletjournal.us/home/index.html repository: https://github.com/singerdmx/flutter-quill/tree/master/flutter_quill_extensions @@ -14,19 +14,14 @@ dependencies: flutter_quill: ^7.4.7 + gal: ^2.1.1 http: ^1.1.0 - image_picker: ">=1.0.4" + image_picker: ">=0.8.5 <2.0.0" + math_keyboard: ">=0.1.8 <0.3.0" photo_view: ^0.14.0 - video_player: ^2.7.2 - youtube_player_flutter: ^8.1.2 - # gallery_saver: ^2.1.1 - math_keyboard: ">=0.2.1" - # string_validator: ^1.0.0 - universal_html: ^2.2.4 - # url_launcher: ^6.1.14 - # dio: ^5.3.3 - - gal: ^2.1.1 + universal_html: ^2.2.1 + video_player: ^2.7.0 + youtube_player_flutter: ^8.1.1 dev_dependencies: flutter_test: From 8cb14b8155219a94c612467df79206ff09b9b386 Mon Sep 17 00:00:00 2001 From: Jonathan Salmon Date: Wed, 4 Oct 2023 23:14:18 +0100 Subject: [PATCH 7/7] extensions: resolve missing package --- flutter_quill_extensions/pubspec.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/flutter_quill_extensions/pubspec.yaml b/flutter_quill_extensions/pubspec.yaml index 0ea3297a..c3019116 100644 --- a/flutter_quill_extensions/pubspec.yaml +++ b/flutter_quill_extensions/pubspec.yaml @@ -20,6 +20,7 @@ dependencies: math_keyboard: ">=0.1.8 <0.3.0" 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