Update flutter_quill_extensions part 2 (#1519)
* Update flutter_quill_extensions part 2pull/1520/head
parent
ebd2729f39
commit
c769b14463
22 changed files with 586 additions and 380 deletions
@ -0,0 +1,48 @@ |
|||||||
|
# Todo |
||||||
|
|
||||||
|
This is a todo list page that added recently and will be updated soon. |
||||||
|
|
||||||
|
## Table of contents |
||||||
|
- [Todo](#todo) |
||||||
|
- [Table of contents](#table-of-contents) |
||||||
|
- [Flutter Quill](#flutter-quill) |
||||||
|
- [Features](#features) |
||||||
|
- [Improvemenets](#improvemenets) |
||||||
|
- [Bugs](#bugs) |
||||||
|
- [Flutter Quill Extensions](#flutter-quill-extensions) |
||||||
|
- [Features](#features-1) |
||||||
|
- [Improvemenets](#improvemenets-1) |
||||||
|
- [Bugs](#bugs-1) |
||||||
|
|
||||||
|
## Flutter Quill |
||||||
|
|
||||||
|
### Features |
||||||
|
|
||||||
|
1. Add a method to set TextInputAction, fore more [info](https://github.com/singerdmx/flutter-quill/issues/1328) |
||||||
|
2. Add support for Text magnification feature, for more [info](https://github.com/singerdmx/flutter-quill/issues/1504) |
||||||
|
3. Provide a way to expose quills undo redo stacks, for more [info](https://github.com/singerdmx/flutter-quill/issues/1381) |
||||||
|
|
||||||
|
### Improvemenets |
||||||
|
|
||||||
|
1. Improve the Raw Quill Editor, for more [info](https://github.com/singerdmx/flutter-quill/issues/1509) |
||||||
|
2. Provide more support to all the platforms |
||||||
|
|
||||||
|
### Bugs |
||||||
|
|
||||||
|
Empty for now. |
||||||
|
Please go to the [issues](https://github.com/singerdmx/flutter-quill/issues) |
||||||
|
|
||||||
|
|
||||||
|
## Flutter Quill Extensions |
||||||
|
|
||||||
|
### Features |
||||||
|
1. Add support for cropping an image, fore more [info](https://github.com/singerdmx/flutter-quill/issues/1494) |
||||||
|
2. Add support for copying images to the Clipboard |
||||||
|
|
||||||
|
### Improvemenets |
||||||
|
|
||||||
|
Please check the todos, this list will be updated soon. |
||||||
|
|
||||||
|
### Bugs |
||||||
|
|
||||||
|
Please check the todos, this list will be updated soon. |
@ -0,0 +1,195 @@ |
|||||||
|
import 'package:flutter/cupertino.dart' show showCupertinoModalPopup; |
||||||
|
import 'package:flutter/material.dart'; |
||||||
|
// import 'package:flutter/services.dart' show Clipboard, ClipboardData; |
||||||
|
import 'package:flutter_quill/extensions.dart' |
||||||
|
show isDesktop, isMobile, replaceStyleStringWithSize; |
||||||
|
import 'package:flutter_quill/flutter_quill.dart' |
||||||
|
show ImageUrl, QuillController, StyleAttribute, getEmbedNode; |
||||||
|
import 'package:flutter_quill/translations.dart'; |
||||||
|
|
||||||
|
import '../../../../logic/services/image_saver/s_image_saver.dart'; |
||||||
|
import '../../../models/config/editor/image/image.dart'; |
||||||
|
import '../../utils.dart'; |
||||||
|
import '../../widgets/image.dart' show ImageTapWrapper, getImageStyleString; |
||||||
|
import '../../widgets/image_resizer.dart' show ImageResizer; |
||||||
|
import 'image.dart' show OptionalSize; |
||||||
|
|
||||||
|
class ImageOptionsMenu extends StatelessWidget { |
||||||
|
const ImageOptionsMenu({ |
||||||
|
required this.controller, |
||||||
|
required this.configurations, |
||||||
|
required this.imageSource, |
||||||
|
required this.imageSize, |
||||||
|
required this.isReadOnly, |
||||||
|
required this.imageSaverService, |
||||||
|
super.key, |
||||||
|
}); |
||||||
|
|
||||||
|
final QuillController controller; |
||||||
|
final QuillEditorImageEmbedConfigurations configurations; |
||||||
|
final String imageSource; |
||||||
|
final OptionalSize imageSize; |
||||||
|
final bool isReadOnly; |
||||||
|
final ImageSaverService imageSaverService; |
||||||
|
|
||||||
|
@override |
||||||
|
Widget build(BuildContext context) { |
||||||
|
final materialTheme = Theme.of(context); |
||||||
|
return Padding( |
||||||
|
padding: const EdgeInsets.fromLTRB(50, 0, 50, 0), |
||||||
|
child: SimpleDialog( |
||||||
|
title: Text('Image'.i18n), |
||||||
|
children: [ |
||||||
|
if (!isReadOnly) |
||||||
|
ListTile( |
||||||
|
title: Text('Resize'.i18n), |
||||||
|
leading: const Icon(Icons.settings_outlined), |
||||||
|
onTap: () { |
||||||
|
Navigator.pop(context); |
||||||
|
showCupertinoModalPopup<void>( |
||||||
|
context: context, |
||||||
|
builder: (context) { |
||||||
|
final screenSize = MediaQuery.sizeOf(context); |
||||||
|
return ImageResizer( |
||||||
|
onImageResize: (w, h) { |
||||||
|
final res = getEmbedNode( |
||||||
|
controller, |
||||||
|
controller.selection.start, |
||||||
|
); |
||||||
|
|
||||||
|
final attr = replaceStyleStringWithSize( |
||||||
|
getImageStyleString(controller), |
||||||
|
width: w, |
||||||
|
height: h, |
||||||
|
isMobile: isMobile(supportWeb: false), |
||||||
|
); |
||||||
|
controller |
||||||
|
..skipRequestKeyboard = true |
||||||
|
..formatText( |
||||||
|
res.offset, |
||||||
|
1, |
||||||
|
StyleAttribute(attr), |
||||||
|
); |
||||||
|
}, |
||||||
|
imageWidth: imageSize.width, |
||||||
|
imageHeight: imageSize.height, |
||||||
|
maxWidth: screenSize.width, |
||||||
|
maxHeight: screenSize.height, |
||||||
|
); |
||||||
|
}, |
||||||
|
); |
||||||
|
}, |
||||||
|
), |
||||||
|
ListTile( |
||||||
|
leading: const Icon(Icons.copy_all_outlined), |
||||||
|
title: Text('Copy'.i18n), |
||||||
|
onTap: () async { |
||||||
|
final navigator = Navigator.of(context); |
||||||
|
final imageNode = |
||||||
|
getEmbedNode(controller, controller.selection.start).value; |
||||||
|
final imageUrl = imageNode.value.data; |
||||||
|
controller.copiedImageUrl = ImageUrl( |
||||||
|
imageUrl, |
||||||
|
getImageStyleString(controller), |
||||||
|
); |
||||||
|
// TODO: Implement the copy image |
||||||
|
// await Clipboard.setData( |
||||||
|
// ClipboardData(text: '$imageUrl'), |
||||||
|
// ); |
||||||
|
navigator.pop(); |
||||||
|
}, |
||||||
|
), |
||||||
|
if (!isReadOnly) |
||||||
|
ListTile( |
||||||
|
leading: Icon( |
||||||
|
Icons.delete_forever_outlined, |
||||||
|
color: materialTheme.colorScheme.error, |
||||||
|
), |
||||||
|
title: Text('Remove'.i18n), |
||||||
|
onTap: () async { |
||||||
|
Navigator.of(context).pop(); |
||||||
|
|
||||||
|
// Call the remove check callback if set |
||||||
|
if (await configurations.shouldRemoveImageCallback |
||||||
|
?.call(imageSource) == |
||||||
|
false) { |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
final offset = getEmbedNode( |
||||||
|
controller, |
||||||
|
controller.selection.start, |
||||||
|
).offset; |
||||||
|
controller.replaceText( |
||||||
|
offset, |
||||||
|
1, |
||||||
|
'', |
||||||
|
TextSelection.collapsed(offset: offset), |
||||||
|
); |
||||||
|
// Call the post remove callback if set |
||||||
|
await configurations.onImageRemovedCallback.call(imageSource); |
||||||
|
}, |
||||||
|
), |
||||||
|
...[ |
||||||
|
ListTile( |
||||||
|
leading: const Icon(Icons.save), |
||||||
|
title: Text('Save'.i18n), |
||||||
|
enabled: !isDesktop(supportWeb: false), |
||||||
|
onTap: () async { |
||||||
|
final messenger = ScaffoldMessenger.of(context); |
||||||
|
Navigator.of(context).pop(); |
||||||
|
|
||||||
|
final saveImageResult = await saveImage( |
||||||
|
imageUrl: imageSource, |
||||||
|
imageSaverService: imageSaverService, |
||||||
|
); |
||||||
|
final imageSavedSuccessfully = saveImageResult.isSuccess; |
||||||
|
|
||||||
|
messenger.clearSnackBars(); |
||||||
|
|
||||||
|
if (!imageSavedSuccessfully) { |
||||||
|
messenger.showSnackBar(SnackBar( |
||||||
|
content: Text( |
||||||
|
'Error while saving image'.i18n, |
||||||
|
))); |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
String message; |
||||||
|
switch (saveImageResult.method) { |
||||||
|
case SaveImageResultMethod.network: |
||||||
|
message = 'Saved using the network'.i18n; |
||||||
|
break; |
||||||
|
case SaveImageResultMethod.localStorage: |
||||||
|
message = 'Saved using the local storage'.i18n; |
||||||
|
break; |
||||||
|
} |
||||||
|
|
||||||
|
messenger.showSnackBar( |
||||||
|
SnackBar( |
||||||
|
content: Text(message), |
||||||
|
), |
||||||
|
); |
||||||
|
}, |
||||||
|
), |
||||||
|
ListTile( |
||||||
|
leading: const Icon(Icons.zoom_in), |
||||||
|
title: Text('Zoom'.i18n), |
||||||
|
onTap: () => Navigator.pushReplacement( |
||||||
|
context, |
||||||
|
MaterialPageRoute( |
||||||
|
builder: (context) => ImageTapWrapper( |
||||||
|
imageUrl: imageSource, |
||||||
|
imageProviderBuilder: configurations.imageProviderBuilder, |
||||||
|
imageErrorWidgetBuilder: |
||||||
|
configurations.imageErrorWidgetBuilder, |
||||||
|
), |
||||||
|
), |
||||||
|
), |
||||||
|
), |
||||||
|
], |
||||||
|
], |
||||||
|
), |
||||||
|
); |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue