Rich text editor for Flutter
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

288 lines
9.7 KiB

import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_quill/extensions.dart' as base;
import 'package:flutter_quill/flutter_quill.dart' hide Text;
import 'package:flutter_quill/translations.dart';
import 'package:gallery_saver/gallery_saver.dart';
import 'package:math_keyboard/math_keyboard.dart';
import 'utils.dart';
import 'widgets/image.dart';
import 'widgets/image_resizer.dart';
import 'widgets/video_app.dart';
import 'widgets/youtube_video_app.dart';
class ImageEmbedBuilder extends EmbedBuilder {
@override
String get key => BlockEmbed.imageType;
@override
Widget build(
BuildContext context,
QuillController controller,
base.Embed node,
bool readOnly,
bool inline,
) {
assert(!kIsWeb, 'Please provide image EmbedBuilder for Web');
var image;
final imageUrl = standardizeImageUrl(node.value.data);
Remove tuples (#1128) * Update dependencies of `flutter_quill_extensions` * Override `intl` in example Running "flutter pub get" in example... Resolving dependencies... (1.0s) Because every version of flutter_quill from path depends on i18n_extension ^7.0.0 and no versions of i18n_extension match >7.0.0 <8.0.0, every version of flutter_quill from path requires i18n_extension 7.0.0. And because i18n_extension 7.0.0 depends on intl ^0.18.0 and math_keyboard 0.1.8 depends on intl ^0.17.0, flutter_quill from path is incompatible with math_keyboard 0.1.8. Because every version of flutter_quill_extensions from path depends on math_keyboard ^0.1.8 and no versions of math_keyboard match >0.1.8 <0.2.0, every version of flutter_quill_extensions from path requires math_keyboard 0.1.8. Thus, flutter_quill from path is incompatible with flutter_quill_extensions from path. So, because app depends on both flutter_quill_extensions from path and flutter_quill from path, version solving failed. pub get failed * Remove all `tuple` imports * Create struct for vertical spacing * Create struct for history items * Create struct for individual styles offsetvalue * Override `intl` in `flutter_quill_extensions` * Create struct for (nullable) image width/height * Create struct for image url * Create struct for text links * Create struct for glyph heights * Use `OffsetValue` struct for embed node * Create struct for next new line * Create struct for segment leaf nodes * Create struct for history undo/redo result * Downgrade `i18n_extension` to `6.0.0` * Bump to 7.0.0 Required for `flutter_quill_extensions` to have access to the new structs.
2 years ago
OptionalSize? _imageSize;
final style = node.style.attributes['style'];
if (base.isMobile() && style != null) {
final _attrs = base.parseKeyValuePairs(style.value.toString(), {
Attribute.mobileWidth,
Attribute.mobileHeight,
Attribute.mobileMargin,
Attribute.mobileAlignment
});
if (_attrs.isNotEmpty) {
assert(
_attrs[Attribute.mobileWidth] != null &&
_attrs[Attribute.mobileHeight] != null,
'mobileWidth and mobileHeight must be specified');
final w = double.parse(_attrs[Attribute.mobileWidth]!);
final h = double.parse(_attrs[Attribute.mobileHeight]!);
Remove tuples (#1128) * Update dependencies of `flutter_quill_extensions` * Override `intl` in example Running "flutter pub get" in example... Resolving dependencies... (1.0s) Because every version of flutter_quill from path depends on i18n_extension ^7.0.0 and no versions of i18n_extension match >7.0.0 <8.0.0, every version of flutter_quill from path requires i18n_extension 7.0.0. And because i18n_extension 7.0.0 depends on intl ^0.18.0 and math_keyboard 0.1.8 depends on intl ^0.17.0, flutter_quill from path is incompatible with math_keyboard 0.1.8. Because every version of flutter_quill_extensions from path depends on math_keyboard ^0.1.8 and no versions of math_keyboard match >0.1.8 <0.2.0, every version of flutter_quill_extensions from path requires math_keyboard 0.1.8. Thus, flutter_quill from path is incompatible with flutter_quill_extensions from path. So, because app depends on both flutter_quill_extensions from path and flutter_quill from path, version solving failed. pub get failed * Remove all `tuple` imports * Create struct for vertical spacing * Create struct for history items * Create struct for individual styles offsetvalue * Override `intl` in `flutter_quill_extensions` * Create struct for (nullable) image width/height * Create struct for image url * Create struct for text links * Create struct for glyph heights * Use `OffsetValue` struct for embed node * Create struct for next new line * Create struct for segment leaf nodes * Create struct for history undo/redo result * Downgrade `i18n_extension` to `6.0.0` * Bump to 7.0.0 Required for `flutter_quill_extensions` to have access to the new structs.
2 years ago
_imageSize = OptionalSize(w, h);
final m = _attrs[Attribute.mobileMargin] == null
? 0.0
: double.parse(_attrs[Attribute.mobileMargin]!);
final a = base.getAlignment(_attrs[Attribute.mobileAlignment]);
image = Padding(
padding: EdgeInsets.all(m),
child: imageByUrl(imageUrl, width: w, height: h, alignment: a));
}
}
Remove tuples (#1128) * Update dependencies of `flutter_quill_extensions` * Override `intl` in example Running "flutter pub get" in example... Resolving dependencies... (1.0s) Because every version of flutter_quill from path depends on i18n_extension ^7.0.0 and no versions of i18n_extension match >7.0.0 <8.0.0, every version of flutter_quill from path requires i18n_extension 7.0.0. And because i18n_extension 7.0.0 depends on intl ^0.18.0 and math_keyboard 0.1.8 depends on intl ^0.17.0, flutter_quill from path is incompatible with math_keyboard 0.1.8. Because every version of flutter_quill_extensions from path depends on math_keyboard ^0.1.8 and no versions of math_keyboard match >0.1.8 <0.2.0, every version of flutter_quill_extensions from path requires math_keyboard 0.1.8. Thus, flutter_quill from path is incompatible with flutter_quill_extensions from path. So, because app depends on both flutter_quill_extensions from path and flutter_quill from path, version solving failed. pub get failed * Remove all `tuple` imports * Create struct for vertical spacing * Create struct for history items * Create struct for individual styles offsetvalue * Override `intl` in `flutter_quill_extensions` * Create struct for (nullable) image width/height * Create struct for image url * Create struct for text links * Create struct for glyph heights * Use `OffsetValue` struct for embed node * Create struct for next new line * Create struct for segment leaf nodes * Create struct for history undo/redo result * Downgrade `i18n_extension` to `6.0.0` * Bump to 7.0.0 Required for `flutter_quill_extensions` to have access to the new structs.
2 years ago
if (_imageSize == null) {
image = imageByUrl(imageUrl);
Remove tuples (#1128) * Update dependencies of `flutter_quill_extensions` * Override `intl` in example Running "flutter pub get" in example... Resolving dependencies... (1.0s) Because every version of flutter_quill from path depends on i18n_extension ^7.0.0 and no versions of i18n_extension match >7.0.0 <8.0.0, every version of flutter_quill from path requires i18n_extension 7.0.0. And because i18n_extension 7.0.0 depends on intl ^0.18.0 and math_keyboard 0.1.8 depends on intl ^0.17.0, flutter_quill from path is incompatible with math_keyboard 0.1.8. Because every version of flutter_quill_extensions from path depends on math_keyboard ^0.1.8 and no versions of math_keyboard match >0.1.8 <0.2.0, every version of flutter_quill_extensions from path requires math_keyboard 0.1.8. Thus, flutter_quill from path is incompatible with flutter_quill_extensions from path. So, because app depends on both flutter_quill_extensions from path and flutter_quill from path, version solving failed. pub get failed * Remove all `tuple` imports * Create struct for vertical spacing * Create struct for history items * Create struct for individual styles offsetvalue * Override `intl` in `flutter_quill_extensions` * Create struct for (nullable) image width/height * Create struct for image url * Create struct for text links * Create struct for glyph heights * Use `OffsetValue` struct for embed node * Create struct for next new line * Create struct for segment leaf nodes * Create struct for history undo/redo result * Downgrade `i18n_extension` to `6.0.0` * Bump to 7.0.0 Required for `flutter_quill_extensions` to have access to the new structs.
2 years ago
_imageSize = OptionalSize((image as Image).width, image.height);
}
if (!readOnly && base.isMobile()) {
return GestureDetector(
onTap: () {
showDialog(
context: context,
builder: (context) {
final resizeOption = _SimpleDialogItem(
icon: Icons.settings_outlined,
color: Colors.lightBlueAccent,
text: 'Resize'.i18n,
onPressed: () {
Navigator.pop(context);
showCupertinoModalPopup<void>(
context: context,
builder: (context) {
final _screenSize = MediaQuery.of(context).size;
return ImageResizer(
onImageResize: (w, h) {
final res = getEmbedNode(
controller, controller.selection.start);
final attr = base.replaceStyleString(
getImageStyleString(controller), w, h);
controller
..skipRequestKeyboard = true
..formatText(
Remove tuples (#1128) * Update dependencies of `flutter_quill_extensions` * Override `intl` in example Running "flutter pub get" in example... Resolving dependencies... (1.0s) Because every version of flutter_quill from path depends on i18n_extension ^7.0.0 and no versions of i18n_extension match >7.0.0 <8.0.0, every version of flutter_quill from path requires i18n_extension 7.0.0. And because i18n_extension 7.0.0 depends on intl ^0.18.0 and math_keyboard 0.1.8 depends on intl ^0.17.0, flutter_quill from path is incompatible with math_keyboard 0.1.8. Because every version of flutter_quill_extensions from path depends on math_keyboard ^0.1.8 and no versions of math_keyboard match >0.1.8 <0.2.0, every version of flutter_quill_extensions from path requires math_keyboard 0.1.8. Thus, flutter_quill from path is incompatible with flutter_quill_extensions from path. So, because app depends on both flutter_quill_extensions from path and flutter_quill from path, version solving failed. pub get failed * Remove all `tuple` imports * Create struct for vertical spacing * Create struct for history items * Create struct for individual styles offsetvalue * Override `intl` in `flutter_quill_extensions` * Create struct for (nullable) image width/height * Create struct for image url * Create struct for text links * Create struct for glyph heights * Use `OffsetValue` struct for embed node * Create struct for next new line * Create struct for segment leaf nodes * Create struct for history undo/redo result * Downgrade `i18n_extension` to `6.0.0` * Bump to 7.0.0 Required for `flutter_quill_extensions` to have access to the new structs.
2 years ago
res.offset, 1, StyleAttribute(attr));
},
Remove tuples (#1128) * Update dependencies of `flutter_quill_extensions` * Override `intl` in example Running "flutter pub get" in example... Resolving dependencies... (1.0s) Because every version of flutter_quill from path depends on i18n_extension ^7.0.0 and no versions of i18n_extension match >7.0.0 <8.0.0, every version of flutter_quill from path requires i18n_extension 7.0.0. And because i18n_extension 7.0.0 depends on intl ^0.18.0 and math_keyboard 0.1.8 depends on intl ^0.17.0, flutter_quill from path is incompatible with math_keyboard 0.1.8. Because every version of flutter_quill_extensions from path depends on math_keyboard ^0.1.8 and no versions of math_keyboard match >0.1.8 <0.2.0, every version of flutter_quill_extensions from path requires math_keyboard 0.1.8. Thus, flutter_quill from path is incompatible with flutter_quill_extensions from path. So, because app depends on both flutter_quill_extensions from path and flutter_quill from path, version solving failed. pub get failed * Remove all `tuple` imports * Create struct for vertical spacing * Create struct for history items * Create struct for individual styles offsetvalue * Override `intl` in `flutter_quill_extensions` * Create struct for (nullable) image width/height * Create struct for image url * Create struct for text links * Create struct for glyph heights * Use `OffsetValue` struct for embed node * Create struct for next new line * Create struct for segment leaf nodes * Create struct for history undo/redo result * Downgrade `i18n_extension` to `6.0.0` * Bump to 7.0.0 Required for `flutter_quill_extensions` to have access to the new structs.
2 years ago
imageWidth: _imageSize?.width,
imageHeight: _imageSize?.height,
maxWidth: _screenSize.width,
maxHeight: _screenSize.height);
});
},
);
final copyOption = _SimpleDialogItem(
icon: Icons.copy_all_outlined,
color: Colors.cyanAccent,
text: 'Copy'.i18n,
onPressed: () {
final imageNode =
getEmbedNode(controller, controller.selection.start)
Remove tuples (#1128) * Update dependencies of `flutter_quill_extensions` * Override `intl` in example Running "flutter pub get" in example... Resolving dependencies... (1.0s) Because every version of flutter_quill from path depends on i18n_extension ^7.0.0 and no versions of i18n_extension match >7.0.0 <8.0.0, every version of flutter_quill from path requires i18n_extension 7.0.0. And because i18n_extension 7.0.0 depends on intl ^0.18.0 and math_keyboard 0.1.8 depends on intl ^0.17.0, flutter_quill from path is incompatible with math_keyboard 0.1.8. Because every version of flutter_quill_extensions from path depends on math_keyboard ^0.1.8 and no versions of math_keyboard match >0.1.8 <0.2.0, every version of flutter_quill_extensions from path requires math_keyboard 0.1.8. Thus, flutter_quill from path is incompatible with flutter_quill_extensions from path. So, because app depends on both flutter_quill_extensions from path and flutter_quill from path, version solving failed. pub get failed * Remove all `tuple` imports * Create struct for vertical spacing * Create struct for history items * Create struct for individual styles offsetvalue * Override `intl` in `flutter_quill_extensions` * Create struct for (nullable) image width/height * Create struct for image url * Create struct for text links * Create struct for glyph heights * Use `OffsetValue` struct for embed node * Create struct for next new line * Create struct for segment leaf nodes * Create struct for history undo/redo result * Downgrade `i18n_extension` to `6.0.0` * Bump to 7.0.0 Required for `flutter_quill_extensions` to have access to the new structs.
2 years ago
.value;
final imageUrl = imageNode.value.data;
controller.copiedImageUrl =
Remove tuples (#1128) * Update dependencies of `flutter_quill_extensions` * Override `intl` in example Running "flutter pub get" in example... Resolving dependencies... (1.0s) Because every version of flutter_quill from path depends on i18n_extension ^7.0.0 and no versions of i18n_extension match >7.0.0 <8.0.0, every version of flutter_quill from path requires i18n_extension 7.0.0. And because i18n_extension 7.0.0 depends on intl ^0.18.0 and math_keyboard 0.1.8 depends on intl ^0.17.0, flutter_quill from path is incompatible with math_keyboard 0.1.8. Because every version of flutter_quill_extensions from path depends on math_keyboard ^0.1.8 and no versions of math_keyboard match >0.1.8 <0.2.0, every version of flutter_quill_extensions from path requires math_keyboard 0.1.8. Thus, flutter_quill from path is incompatible with flutter_quill_extensions from path. So, because app depends on both flutter_quill_extensions from path and flutter_quill from path, version solving failed. pub get failed * Remove all `tuple` imports * Create struct for vertical spacing * Create struct for history items * Create struct for individual styles offsetvalue * Override `intl` in `flutter_quill_extensions` * Create struct for (nullable) image width/height * Create struct for image url * Create struct for text links * Create struct for glyph heights * Use `OffsetValue` struct for embed node * Create struct for next new line * Create struct for segment leaf nodes * Create struct for history undo/redo result * Downgrade `i18n_extension` to `6.0.0` * Bump to 7.0.0 Required for `flutter_quill_extensions` to have access to the new structs.
2 years ago
ImageUrl(imageUrl, getImageStyleString(controller));
Navigator.pop(context);
},
);
final removeOption = _SimpleDialogItem(
icon: Icons.delete_forever_outlined,
color: Colors.red.shade200,
text: 'Remove'.i18n,
onPressed: () {
final offset =
getEmbedNode(controller, controller.selection.start)
Remove tuples (#1128) * Update dependencies of `flutter_quill_extensions` * Override `intl` in example Running "flutter pub get" in example... Resolving dependencies... (1.0s) Because every version of flutter_quill from path depends on i18n_extension ^7.0.0 and no versions of i18n_extension match >7.0.0 <8.0.0, every version of flutter_quill from path requires i18n_extension 7.0.0. And because i18n_extension 7.0.0 depends on intl ^0.18.0 and math_keyboard 0.1.8 depends on intl ^0.17.0, flutter_quill from path is incompatible with math_keyboard 0.1.8. Because every version of flutter_quill_extensions from path depends on math_keyboard ^0.1.8 and no versions of math_keyboard match >0.1.8 <0.2.0, every version of flutter_quill_extensions from path requires math_keyboard 0.1.8. Thus, flutter_quill from path is incompatible with flutter_quill_extensions from path. So, because app depends on both flutter_quill_extensions from path and flutter_quill from path, version solving failed. pub get failed * Remove all `tuple` imports * Create struct for vertical spacing * Create struct for history items * Create struct for individual styles offsetvalue * Override `intl` in `flutter_quill_extensions` * Create struct for (nullable) image width/height * Create struct for image url * Create struct for text links * Create struct for glyph heights * Use `OffsetValue` struct for embed node * Create struct for next new line * Create struct for segment leaf nodes * Create struct for history undo/redo result * Downgrade `i18n_extension` to `6.0.0` * Bump to 7.0.0 Required for `flutter_quill_extensions` to have access to the new structs.
2 years ago
.offset;
controller.replaceText(offset, 1, '',
TextSelection.collapsed(offset: offset));
Navigator.pop(context);
},
);
return Padding(
padding: const EdgeInsets.fromLTRB(50, 0, 50, 0),
child: SimpleDialog(
shape: const RoundedRectangleBorder(
borderRadius:
BorderRadius.all(Radius.circular(10))),
children: [resizeOption, copyOption, removeOption]),
);
});
},
child: image);
}
if (!readOnly || !base.isMobile() || isImageBase64(imageUrl)) {
return image;
}
// We provide option menu for mobile platform excluding base64 image
return _menuOptionsForReadonlyImage(context, imageUrl, image);
}
}
class VideoEmbedBuilder extends EmbedBuilder {
VideoEmbedBuilder({this.onVideoInit});
final void Function(GlobalKey videoContainerKey)? onVideoInit;
@override
String get key => BlockEmbed.videoType;
@override
Widget build(
BuildContext context,
QuillController controller,
base.Embed node,
bool readOnly,
bool inline,
) {
assert(!kIsWeb, 'Please provide video EmbedBuilder for Web');
final videoUrl = node.value.data;
if (videoUrl.contains('youtube.com') || videoUrl.contains('youtu.be')) {
return YoutubeVideoApp(
videoUrl: videoUrl, context: context, readOnly: readOnly);
}
return VideoApp(
videoUrl: videoUrl,
context: context,
readOnly: readOnly,
onVideoInit: onVideoInit,
);
}
}
class FormulaEmbedBuilder extends EmbedBuilder {
@override
String get key => BlockEmbed.formulaType;
@override
Widget build(
BuildContext context,
QuillController controller,
base.Embed node,
bool readOnly,
bool inline,
) {
assert(!kIsWeb, 'Please provide formula EmbedBuilder for Web');
final mathController = MathFieldEditingController();
return Focus(
onFocusChange: (hasFocus) {
if (hasFocus) {
// If the MathField is tapped, hides the built in keyboard
SystemChannels.textInput.invokeMethod('TextInput.hide');
debugPrint(mathController.currentEditingValue());
}
},
child: MathField(
controller: mathController,
variables: const ['x', 'y', 'z'],
onChanged: (value) {},
onSubmitted: (value) {},
),
);
}
}
Widget _menuOptionsForReadonlyImage(
BuildContext context, String imageUrl, Widget image) {
return GestureDetector(
onTap: () {
showDialog(
context: context,
builder: (context) {
final saveOption = _SimpleDialogItem(
icon: Icons.save,
color: Colors.greenAccent,
text: 'Save'.i18n,
onPressed: () {
imageUrl = appendFileExtensionToImageUrl(imageUrl);
GallerySaver.saveImage(imageUrl).then((_) {
ScaffoldMessenger.of(context)
.showSnackBar(SnackBar(content: Text('Saved'.i18n)));
Navigator.pop(context);
});
},
);
final zoomOption = _SimpleDialogItem(
icon: Icons.zoom_in,
color: Colors.cyanAccent,
text: 'Zoom'.i18n,
onPressed: () {
Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (context) =>
ImageTapWrapper(imageUrl: imageUrl)));
},
);
return Padding(
padding: const EdgeInsets.fromLTRB(50, 0, 50, 0),
child: SimpleDialog(
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(10))),
children: [saveOption, zoomOption]),
);
});
},
child: image);
}
class _SimpleDialogItem extends StatelessWidget {
const _SimpleDialogItem(
{required this.icon,
required this.color,
required this.text,
required this.onPressed,
Key? key})
: super(key: key);
final IconData icon;
final Color color;
final String text;
final VoidCallback onPressed;
@override
Widget build(BuildContext context) {
return SimpleDialogOption(
onPressed: onPressed,
child: Row(
children: [
Icon(icon, size: 36, color: color),
Padding(
padding: const EdgeInsetsDirectional.only(start: 16),
child:
Text(text, style: const TextStyle(fontWeight: FontWeight.bold)),
),
],
),
);
}
}