Version 9.0.0 (#1566)

* Prepare for Version 9.0.0
pull/1577/head
Ellet 1 year ago committed by GitHub
parent 363437deaf
commit c02699071a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      .github/PULL_REQUEST_TEMPLATE.md
  2. 3
      .github/workflows/build.yml
  3. 3
      .github/workflows/main.yml
  4. 23
      .github/workflows/publish.yml
  5. 3
      .pubignore
  6. 52
      CHANGELOG.md
  7. 2
      CONTRIBUTING.md
  8. 22
      README.md
  9. 6
      doc/development_notes.md
  10. 431
      doc/migration.md
  11. 429
      doc/migration/7_8.md
  12. 83
      doc/migration/8_9.md
  13. 9
      doc/todo.md
  14. 2
      doc/translation.md
  15. 2
      example/android/app/build.gradle
  16. 16
      example/android/app/src/main/AndroidManifest.xml
  17. 2
      example/android/build.gradle
  18. 2
      example/android/gradle/wrapper/gradle-wrapper.properties
  19. 3
      example/lib/presentation/quill/my_quill_editor.dart
  20. 151
      example/lib/presentation/quill/my_quill_toolbar.dart
  21. 64
      example/lib/presentation/quill/quill_screen.dart
  22. 6
      example/lib/presentation/quill/samples/quill_images_sample.dart
  23. 36
      example/lib/presentation/simple/simple_screen.dart
  24. 12
      example/linux/flutter/generated_plugin_registrant.cc
  25. 3
      example/linux/flutter/generated_plugins.cmake
  26. 6
      example/macos/Flutter/GeneratedPluginRegistrant.swift
  27. 16
      example/macos/Podfile.lock
  28. 15
      example/pubspec.yaml
  29. 9
      example/windows/flutter/generated_plugin_registrant.cc
  30. 3
      example/windows/flutter/generated_plugins.cmake
  31. 1672
      flutter_quill_extensions/CHANGELOG.md
  32. 26
      flutter_quill_extensions/README.md
  33. 13
      flutter_quill_extensions/lib/embeds/formula/toolbar/formula_button.dart
  34. 14
      flutter_quill_extensions/lib/embeds/image/editor/image_embed.dart
  35. 3
      flutter_quill_extensions/lib/embeds/image/editor/image_embed_types.dart
  36. 36
      flutter_quill_extensions/lib/embeds/image/editor/image_menu.dart
  37. 17
      flutter_quill_extensions/lib/embeds/image/toolbar/image_button.dart
  38. 6
      flutter_quill_extensions/lib/embeds/image/toolbar/select_image_source.dart
  39. 34
      flutter_quill_extensions/lib/embeds/others/camera_button/camera_button.dart
  40. 50
      flutter_quill_extensions/lib/embeds/others/camera_button/select_camera_action.dart
  41. 36
      flutter_quill_extensions/lib/embeds/others/image_video_utils.dart
  42. 4
      flutter_quill_extensions/lib/embeds/others/media_button/media_button.dart
  43. 5
      flutter_quill_extensions/lib/embeds/video/editor/video_embed.dart
  44. 3
      flutter_quill_extensions/lib/embeds/video/toolbar/select_video_source.dart
  45. 25
      flutter_quill_extensions/lib/embeds/video/toolbar/video_button.dart
  46. 2
      flutter_quill_extensions/lib/embeds/video/video.dart
  47. 7
      flutter_quill_extensions/lib/embeds/widgets/image.dart
  48. 0
      flutter_quill_extensions/lib/extensions/controller_ext.dart
  49. 8
      flutter_quill_extensions/lib/flutter_quill_extensions.dart
  50. 46
      flutter_quill_extensions/lib/models/config/shared_configurations.dart
  51. 73
      flutter_quill_extensions/lib/utils/element_utils/element_shared_utils.dart
  52. 24
      flutter_quill_extensions/lib/utils/element_utils/element_utils.dart
  53. 17
      flutter_quill_extensions/lib/utils/patterns.dart
  54. 28
      flutter_quill_extensions/lib/utils/utils.dart
  55. 8
      flutter_quill_extensions/pubspec.yaml
  56. 1622
      flutter_quill_test/CHANGELOG.md
  57. 4
      flutter_quill_test/pubspec.yaml
  58. 20
      lib/flutter_quill.dart
  59. 5
      lib/markdown_quill.dart
  60. 93
      lib/src/extensions/quill_configurations_ext.dart
  61. 6
      lib/src/extensions/quill_controller_ext.dart
  62. 160
      lib/src/extensions/quill_provider.dart
  63. 11
      lib/src/extensions/uri_ext.dart
  64. 28
      lib/src/l10n/generated/quill_localizations.dart
  65. 18
      lib/src/l10n/generated/quill_localizations_ar.dart
  66. 18
      lib/src/l10n/generated/quill_localizations_bg.dart
  67. 18
      lib/src/l10n/generated/quill_localizations_bn.dart
  68. 18
      lib/src/l10n/generated/quill_localizations_cs.dart
  69. 18
      lib/src/l10n/generated/quill_localizations_da.dart
  70. 18
      lib/src/l10n/generated/quill_localizations_de.dart
  71. 18
      lib/src/l10n/generated/quill_localizations_en.dart
  72. 18
      lib/src/l10n/generated/quill_localizations_es.dart
  73. 18
      lib/src/l10n/generated/quill_localizations_fa.dart
  74. 18
      lib/src/l10n/generated/quill_localizations_fr.dart
  75. 18
      lib/src/l10n/generated/quill_localizations_he.dart
  76. 18
      lib/src/l10n/generated/quill_localizations_hi.dart
  77. 18
      lib/src/l10n/generated/quill_localizations_id.dart
  78. 18
      lib/src/l10n/generated/quill_localizations_it.dart
  79. 18
      lib/src/l10n/generated/quill_localizations_ja.dart
  80. 18
      lib/src/l10n/generated/quill_localizations_ko.dart
  81. 18
      lib/src/l10n/generated/quill_localizations_ms.dart
  82. 18
      lib/src/l10n/generated/quill_localizations_nl.dart
  83. 18
      lib/src/l10n/generated/quill_localizations_no.dart
  84. 18
      lib/src/l10n/generated/quill_localizations_pl.dart
  85. 18
      lib/src/l10n/generated/quill_localizations_pt.dart
  86. 18
      lib/src/l10n/generated/quill_localizations_ru.dart
  87. 18
      lib/src/l10n/generated/quill_localizations_sr.dart
  88. 18
      lib/src/l10n/generated/quill_localizations_sw.dart
  89. 18
      lib/src/l10n/generated/quill_localizations_tk.dart
  90. 18
      lib/src/l10n/generated/quill_localizations_tr.dart
  91. 18
      lib/src/l10n/generated/quill_localizations_uk.dart
  92. 18
      lib/src/l10n/generated/quill_localizations_ur.dart
  93. 18
      lib/src/l10n/generated/quill_localizations_vi.dart
  94. 18
      lib/src/l10n/generated/quill_localizations_zh.dart
  95. 8
      lib/src/l10n/quill_en.arb
  96. 132
      lib/src/l10n/untranslated.json
  97. 4
      lib/src/l10n/widgets/localizations.dart
  98. 21
      lib/src/models/config/editor/editor_configurations.dart
  99. 9
      lib/src/models/config/editor/element_options.dart
  100. 14
      lib/src/models/config/editor/elements/list/ordered_list.dart
  101. Some files were not shown because too many files have changed in this diff Show More

@ -28,7 +28,7 @@
- [ ] I titled the PR using [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0).
- [ ] I did not modify the `CHANGELOG.md` nor the plugin version in `pubspec.yaml` files.
- [ ] All existing and new tests are passing.
- [ ] I have run the commands in `./scripts/before-push.sh` and it all passed successfully
- [ ] I have run the commands in `./scripts/before_push.sh` and it all passed successfully
## Breaking Change

@ -18,6 +18,9 @@ jobs:
- name: Check flutter version
run: flutter --version
- name: Enable Local Dev
run: ./scripts/enable_local_dev.sh
- name: Install dependencies
run: flutter pub get

@ -20,6 +20,9 @@ jobs:
- name: Check flutter version
run: flutter --version
- name: Enable Local Dev
run: ./scripts/enable_local_dev.sh
- name: Install dependencies
run: flutter pub get

@ -16,26 +16,39 @@ jobs:
- uses: subosito/flutter-action@v2
with:
channel: 'stable'
cache: true
- name: Check flutter version
run: flutter --version
- name: Enable Local Dev
run: ./scripts/enable_local_dev.sh
- name: Install dependencies
run: flutter pub get
# Here you can insert custom steps you need
# - run: dart tool/generate-code.dart
- name: Re-generate the translations
run: ./scripts/regenerate-translations.sh
# This is needed in order for the authentication to success
# dart pub token add https://pub.dev --env-var PUB_TOKEN
# Requests to "https://pub.dev" will now be authenticated using the secret token stored in the environment variable "PUB_TOKEN".
- uses: dart-lang/setup-dart@v1
## dart-lang/setup-dart/.github/workflows/publish.yml@v1
# - name: Update the authorization requests to "https://pub.dev" to use the environment variable "PUB_TOKEN".
# run: dart pub token add https://pub.dev --env-var PUB_TOKEN
- name: Publish
- name: Publish flutter_quill
run: flutter pub publish --force
- name: Publish flutter_quill_extensions
run: flutter pub publish --force
working-directory: ./flutter_quill_extensions/
- name: Publish flutter_quill_test
run: flutter pub publish --force
working-directory: ./flutter_quill_test/
- name: Publish quill_html_converter
run: flutter pub publish --force
working-directory: ./packages/quill_html_converter/

@ -11,6 +11,3 @@ example/build/
example/.dart_tool/
scripts/
<!-- flutter_quill_extensions/
flutter_quill_test/
packages/ -->

@ -2,6 +2,58 @@
All notable changes to this project will be documented in this file.
## 9.0.0-dev-8
* Better support for pasting HTML contents from external websites to the editor
* The experimental support of converting the HTML from `quill_html_converter` is now built-in in the `flutter_quill` and removed from there (Breaking change for `quill_html_converter`)
## 9.0.0-dev-7
* Fix a bug in chaning the background/font color of ol/ul list
* Flutter Quill Extensions:
* Fix link bug in the video url
* Fix patterns
## 9.0.0-dev-6
* Move the `child` from `QuillToolbarConfigurations` into `QuillToolbar` directly
* Bug fixes
* Add the ability to change the background and font color of the ol/ul elements dots and numbers
* Flutter Quill Extensions:
* **Breaking Change**: The `imageProviderBuilder`is now providing the context and image url
## 9.0.0-dev-5
* The `QuillToolbar` is now accepting only `child` with no configurations so you can customize everything you wants, the `QuillToolbar.simple()` or `QuillSimpleToolbar` implements a simple toolbar that is based on `QuillToolbar`, you are free to use it but it just an example and not standard
* Flutter Quill Extensions:
* Improve the camera button
## 9.0.0-dev-4
* The options parameter in all of the buttons is no longer required which can be useful to create custom toolbar with minimal efforts
* Toolbar buttons fixes in both `flutter_quill` and `flutter_quill_extensions`
* The `QuillProvider` has been dropped and no longer used, the providers will be used only internally from now on and we will not using them as much as possible
## 9.0.0-dev-3
* Breaking Changes:
* Rename `QuillToolbar` to `QuillSimpleToolbar`
* Rename `QuillBaseToolbar` to `QuillToolbar`
* Replace `pasteboard` with `rich_cliboard`
* Fix a bug in the example when inserting an image from url
* Flutter Quill Extensions:
* Add support for copying the image to the system cliboard
## 9.0.0-dev-2
* An attemp to fix CI automated publishing
## 9.0.0-dev-1
* An attemp to fix CI automated publishing
## 9.0.0-dev
* **Major Breaking change**: The `QuillProvider` is now optional, the `controller` parameter has been moved to the `QuillEditor` and `QuillToolbar` once again.
* Flutter Quill Extensions;
* **Breaking Change**: Completly change the way how the source code structured to more basic and simple way, organize folders and file names, if you use the library
from `flutter_quill_extensions.dart` then there is nothing you need to do, but if you are using any other import then you need to re-imports
embed, this won't affect how quill js work
* Improvemenets to the image embed
* Add support for `margin` for web
* Add untranslated strings to the `quill_en.arb`
## 8.6.4
* The default value of `keyboardAppearance` for the iOS will be the one from the App/System theme mode instead of always using the `Brightness.light`
* Fix typos in `README.md`

@ -39,7 +39,7 @@ to `pubspec_overrides.yaml` which will be ignored by `.gitignore` and will be us
9. Mention the new changes in the [CHANGELOG.md](../CHANGELOG.md) in the next block
10. Run the following script if possible
```
./scripts/before-push.sh
./scripts/before_push.sh
```
11. When you are done sending your pull request, run:
```

@ -94,17 +94,27 @@ dependencies:
> Your input and insights are valuable in shaping a stable and reliable version for all our users. Thank you for being part of the open-source community!
>
Compatible versions:
<!-- Compatible versions:
| flutter_quill | flutter_quill_extensions | flutter_quill_test |
|-------------------------|--------------------------|-------------------------|
| 8.6.x | 0.7.x | 0.0.5 |
| 8.5.x | 0.6.x | 0.0.5 |
These versions are tested and well-supported, you shouldn't get a build failure
These versions are tested and well-supported, you shouldn't get a build failure -->
## Usage
Before using the package, we must inform you the package use the following plugins:
```
url_launcher
flutter_keyboard_visibility
device_info_plus
super_clipboard
```
All of them doesn't require any platform spesefic setup, except [super_clipboard](https://pub.dev/packages/super_clipboard) which needs some setup on Android only, it's optional but to support copying images and pasting them into editor then you must setup it, open the page in pub.dev and read the `README.md` to get the instructions.
First, you need to instantiate a controller
```dart
@ -228,11 +238,13 @@ To see how to use the extension package, please take a look at the [README](./fl
Having your document stored in Quill Delta format is sometimes not enough. Often you'll need to convert
it to other formats such as HTML to publish it, or send an email.
**Note**: This package support converting from HTML back to Quill delta but it's experimental and used internally when pasting Html content from the cliboard to the Quill Editor
You have two options:
1. Using [quill_html_converter](./packages/quill_html_converter/) to convert to/from HTML, the package can convert the Quill delta to HTML well
(it uses [vsc_quill_delta_to_html](https://pub.dev/packages/vsc_quill_delta_to_html)) but the converting from HTML back to Quill delta is experimental
2. Another option is to use
1. Using [quill_html_converter](./packages/quill_html_converter/) to convert to HTML, the package can convert the Quill delta to HTML well
(it uses [vsc_quill_delta_to_html](https://pub.dev/packages/vsc_quill_delta_to_html)), it just a handy extension to do it more quickly
1. Another option is to use
[vsc_quill_delta_to_html](https://pub.dev/packages/vsc_quill_delta_to_html) to convert your document
to HTML.
This package has full support for all Quill operations—including images, videos, formulas,

@ -1,3 +1,9 @@
# Development notes
- When updating the translations or localizations in the app, please take a look at the [Translation](./translation.md) page as it has important notes in order to work, if you also add a feature that adds new localizations then you need to the instructions of it in order for the translations to take effect
- Only update the `version.dart` and `CHANGELOG.md` at the root folder of the repo, then run the script:
```console
dart ./scripts/regenerate_versions.dart
```
You must mention the changes of the other packages in the repo in the root `CHANGELOG.md` only and the script will replace the `CHANGELOG.md` in the other packages with the root one, and change the version in `pubspec.yaml` with the one in `version.dart` in the root folder

@ -5,435 +5,12 @@ Here you can find the migration guide between different versions, you can contri
- [Migration guide](#migration-guide)
- [from 7.0.0 to 8.0.0](#from-700-to-800)
- [from 8.0.0 to 9.0.0](#from-800-to-900)
## from 7.0.0 to 8.0.0
We have refactored a lot of the base code to allow you to customize everything you want, and it allows us to add new configurations very easily using inherited widgets without passing configurations all over the constructors everywhere which will be very hard to test, fix bugs, and maintain
Open [this](./migration/7_8.md) md file
1. Passing the controller
## from 8.0.0 to 9.0.0
The controller code (should be the same)
```dart
QuillController _controller = QuillController.basic();
```
**Old code**:
```dart
Column(
children: [
QuillToolbar.basic(controller: _controller),
Expanded(
child: QuillEditor.basic(
controller: _controller,
readOnly: false, // true for view only mode
),
)
],
)
```
**New code**:
```dart
QuillProvider(
configurations: QuillConfigurations(
controller: _controller,
sharedConfigurations: const QuillSharedConfigurations(),
),
child: Column(
children: [
const QuillToolbar(),
Expanded(
child: QuillEditor.basic(
configurations: const QuillEditorConfigurations(
readOnly: false, // true for view only mode
),
),
)
],
),
)
```
The `QuillProvider` is an inherited widget that allows you to pass configurations once and use them in the children of it. here we are passing the `_controller` once in the configurations of `QuillProvider` and the `QuillToolbar` and `QuillEditor` will get the `QuillConfigurations` internally, if it doesn't exist you will get an exception.
we also added the `sharedConfigurations` which allow you to configure shared things like the `Local` so you don't have to define them twice, we have removed those from the `QuillToolbar` and `QuillEditor`
2. Regarding The QuillToolbar buttons, we have renamed almost all the buttons, examples:
- `QuillHistory` to `QuillToolbarHistoryButton`
- `IndentButton` to `QuillToolbarIndentButton`
and they usually have two parameters, `controller` and `options`, for example the type for the buttons
- `QuillToolbarHistoryButton` have `QuillToolbarHistoryButtonOptions`
- `QuillToolbarIndentButton` have `QuillToolbarIndentButtonOptions`
- `QuillToolbarClearFormatButton` have `QuillToolbarClearFormatButtonOptions`
All the options have parent `QuillToolbarBaseButtonOptions` which have common things like
```dart
/// By default it will use Icon data from Icons that come from material
/// library for each button, to change this, please pass a different value
/// If there is no Icon in this button then pass null in the child class
final IconData? iconData;
/// To change the icon size pass a different value, by default will be
/// [kDefaultIconSize].
/// This will be used for all the buttons but you can override this
final double globalIconSize;
/// The factor of how much larger the button is in relation to the icon,
/// by default it will be [kIconButtonFactor].
final double globalIconButtonFactor;
/// To do extra logic after pressing the button
final VoidCallback? afterButtonPressed;
/// By default it will use the default tooltip which already localized
final String? tooltip;
/// Use custom theme
final QuillIconTheme? iconTheme;
/// If you want to dispaly a differnet widget based using a builder
final QuillToolbarButtonOptionsChildBuilder<T, I> childBuilder;
/// By default it will be from the one in [QuillProvider]
/// To override it you must pass not null controller
/// if you wish to use the controller in the [childBuilder], please use the
/// one from the extraOptions since it will be not null and will be the one
/// which will be used from the quill toolbar
final QuillController? controller;
```
The `QuillToolbarBaseButtonOptions is`:
```dart
/// The [T] is the option for the button, usually should reference itself
/// it's used in [childBuilder] so the developer can customize this when using it
/// The [I] is an extra option for the button, usually for its state
@immutable
class QuillToolbarBaseButtonOptions<T, I> extends Equatable
```
Example for the clear format button:
```dart
class QuillToolbarClearFormatButtonExtraOptions
extends QuillToolbarBaseButtonExtraOptions {
const QuillToolbarClearFormatButtonExtraOptions({
required super.controller,
required super.context,
required super.onPressed,
});
}
class QuillToolbarClearFormatButtonOptions
extends QuillToolbarBaseButtonOptions<QuillToolbarClearFormatButtonOptions,
QuillToolbarClearFormatButtonExtraOptions> {
const QuillToolbarClearFormatButtonOptions({
super.iconData,
super.afterButtonPressed,
super.childBuilder,
super.controller,
super.iconTheme,
super.tooltip,
this.iconSize,
});
final double? iconSize;
}
```
The base for extra options:
```dart
@immutable
class QuillToolbarBaseButtonExtraOptions extends Equatable {
const QuillToolbarBaseButtonExtraOptions({
required this.controller,
required this.context,
required this.onPressed,
});
/// If you need the not null controller for some usage in the [childBuilder]
/// Then please use this instead of the one in the [options]
final QuillController controller;
/// If the child builder you must use this when the widget is tapped or pressed
/// in order to do what it expected to do
final VoidCallback? onPressed;
final BuildContext context;
@override
List<Object?> get props => [
controller,
];
}
```
which usually share common things, it also add an extra property which was not exist, which is `childBuilder` which allow to rendering of custom widget based on the state of the button and the options it
```dart
QuillToolbar(
configurations: QuillToolbarConfigurations(
buttonOptions: QuillToolbarButtonOptions(
clearFormat: QuillToolbarClearFormatButtonOptions(
childBuilder: (options, extraOptions) {
return IconButton.filled(
onPressed: extraOptions.onPressed,
icon: const Icon(
CupertinoIcons.clear // or options.iconData
),
);
},
),
),
),
),
```
the `extraOptions` usually contains the state variables and the events that you need to trigger like the `onPressed`, it also has the end context and the controller that will be used
while the `options` has the custom controller for each button and it's nullable because there could be no custom controller so we will just use the global one
3. The `QuillToolbar` and `QuillToolbar.basic()` factory constructor
since the basic factory constructor has more options than the original `QuillToolbar` which doesn't make much sense, at least to some developers, we have refactored the `QuillToolbar.basic()` to a different widget called the `QuillToolbar` and the `QuillToolbar` has been renamed to `QuillBaseToolbar` which is the base for `QuillToolbar` or any custom toolbar, sure you can create custom toolbar from scratch by just using the `controller` but if you want more support from the library use the `QuillBaseToolbar`
the children widgets of the new `QuillToolbar` and `QuillEditor` access to their configurations by another two inherited widgets
since `QuillToolbar` and `QuillEditor` take the configuration class and provide them internally using `QuillToolbarProvider` and `QuillEditorProvider`
however the `QuillBaseToolbar` has a little bit different configurations so it has a different provider called `QuillBaseToolbarProvider` and it also already provided by default
But there is one **note**:
> If you are using the toolbar buttons like `QuillToolbarHistoryButton`, `QuillToolbarToggleStyleButton` somewhere like the the custom toolbar (using `QuillBaseToolbar` or any custom widget) then you must provide them with `QuillToolbarProvider` inherited widget, you don't have to do this if you are using the `QuillToolbar` since it will be done for you
>
Example of a custom toolbar:
```dart
QuillProvider(
configurations: QuillConfigurations(
controller: _controller,
sharedConfigurations: const QuillSharedConfigurations(),
),
child: Column(
children: [
QuillToolbarProvider(
toolbarConfigurations: const QuillToolbarConfigurations(),
child: QuillBaseToolbar(
configurations: QuillBaseToolbarConfigurations(
toolbarSize: 15 * 2,
multiRowsDisplay: false,
childrenBuilder: (context) {
final controller = context.requireQuillController; // new extension which is a little bit shorter to access the quill provider then the controller
// there are many options, feel free to explore them all!!
return [
QuillToolbarHistoryButton(
controller: controller,
options: const QuillToolbarHistoryButtonOptions(
isUndo: true),
),
QuillToolbarHistoryButton(
controller: controller,
options: const QuillToolbarHistoryButtonOptions(
isUndo: false),
),
QuillToolbarToggleStyleButton(
attribute: Attribute.bold,
controller: controller,
options: const QuillToolbarToggleStyleButtonOptions(
iconData: Icons.format_bold,
iconSize: 20,
),
),
QuillToolbarToggleStyleButton(
attribute: Attribute.italic,
controller: controller,
options: const QuillToolbarToggleStyleButtonOptions(
iconData: Icons.format_italic,
iconSize: 20,
),
),
QuillToolbarToggleStyleButton(
attribute: Attribute.underline,
controller: controller,
options: const QuillToolbarToggleStyleButtonOptions(
iconData: Icons.format_underline,
iconSize: 20,
),
),
QuillToolbarClearFormatButton(
controller: controller,
options: const QuillToolbarClearFormatButtonOptions(
iconData: Icons.format_clear,
iconSize: 20,
),
),
VerticalDivider(
indent: 12,
endIndent: 12,
color: Colors.grey.shade400,
),
QuillToolbarSelectHeaderStyleButtons(
controller: controller,
options:
const QuillToolbarSelectHeaderStyleButtonsOptions(
iconSize: 20,
),
),
QuillToolbarToggleStyleButton(
attribute: Attribute.ol,
controller: controller,
options: const QuillToolbarToggleStyleButtonOptions(
iconData: Icons.format_list_numbered,
iconSize: 20,
),
),
QuillToolbarToggleStyleButton(
attribute: Attribute.ul,
controller: controller,
options: const QuillToolbarToggleStyleButtonOptions(
iconData: Icons.format_list_bulleted,
iconSize: 20,
),
),
QuillToolbarToggleStyleButton(
attribute: Attribute.blockQuote,
controller: controller,
options: const QuillToolbarToggleStyleButtonOptions(
iconData: Icons.format_quote,
iconSize: 20,
),
),
VerticalDivider(
indent: 12,
endIndent: 12,
color: Colors.grey.shade400,
),
QuillToolbarIndentButton(
controller: controller,
isIncrease: true,
options: const QuillToolbarIndentButtonOptions(
iconData: Icons.format_indent_increase,
iconSize: 20,
)),
QuillToolbarIndentButton(
controller: controller,
isIncrease: false,
options: const QuillToolbarIndentButtonOptions(
iconData: Icons.format_indent_decrease,
iconSize: 20,
),
),
];
},
),
),
),
Expanded(
child: QuillEditor.basic(
configurations: const QuillEditorConfigurations(
readOnly: false,
placeholder: 'Write your notes',
padding: EdgeInsets.all(16),
),
),
)
],
),
)
```
4. The `QuillEditor` and `QuillEditor.basic()`
since the `QuillEditor.basic()` is a lighter version than the original `QuillEditor` since it has fewer required configurations we didn't change much, other than the configuration class, but we must inform you if you plan on sending pull request or you are a maintainer and when you add new property or change anything in `QuillEditorConfigurations` please regenerate the `copyWith` (using IDE extension or plugin) otherwise the `QuilEditor.basic()` will not apply some configurations
we have disabled the line numbers in the code block by default, you can enable them again using the following:
```dart
QuillEditor.basic(
configurations: const QuillEditorConfigurations(
elementOptions: QuillEditorElementOptions(
codeBlock: QuillEditorCodeBlockElementOptions(
enableLineNumbers: true,
),
),
),
)
```
5. `QuillCustomButton`:
We have renamed the property `icon` to `iconData` to indicate it an icon data and not an icon widget
```dart
QuillCustomButton(
iconData: Icons.ac_unit,
onTap: () {
debugPrint('snowflake');
}
),
```
6. Using custom local for both `QuillEditor` and `QuillToolbar`
We have added shared configurations property for shared things
```dart
QuillProvider(
configurations: QuillConfigurations(
controller: _controller,
sharedConfigurations: const QuillSharedConfigurations(
locale: Locale('fr'),
),
),
child: Column(
children: [
const QuillToolbar(
configurations: QuillToolbarConfigurations(),
),
Expanded(
child: QuillEditor.basic(
configurations: const QuillEditorConfigurations(),
),
)
],
),
)
```
7. Image size for all platforms
We have added new properties `width`, `height`, `margin`, `alignment` for all platforms other than mobile and web for the images for example
```dart
{
"insert": {
"image": "https://user-images.githubusercontent.com/122956/72955931-ccc07900-3d52-11ea-89b1-d468a6e2aa2b.png"
},
"attributes":{
"style":"width: 50; height: 50; margin: 10; alignment: topLeft"
}
}
```
8. Other Improvements
You don't need anything to get this done, we have used const more when possible, removed unused events, flutter best practices, converted to stateless widgets when possible, and used better ways to listen for changes example:
instead of
```dart
MediaQuery.of(context).size;
```
we will use
```dart
MediaQuery.sizeOf(context);
```
We also minimized the number of rebuilds using more efficient logic and there is more.
9. More options
We have added more options in the extension package, for all the buttons, configurations, animations, enable and disable things
If you are facing any issues or questions feel free to ask us on GitHub issues
Open [this](./migration/8_9.md) md file

@ -0,0 +1,429 @@
We have refactored a lot of the base code to allow you to customize everything you want, and it allows us to add new configurations very easily using inherited widgets without passing configurations all over the constructors everywhere which will be very hard to test, fix bugs, and maintain
1. Passing the controller
The controller code (should be the same)
```dart
QuillController _controller = QuillController.basic();
```
**Old code**:
```dart
Column(
children: [
QuillToolbar.basic(controller: _controller),
Expanded(
child: QuillEditor.basic(
controller: _controller,
readOnly: false, // true for view only mode
),
)
],
)
```
**New code**:
```dart
QuillProvider(
configurations: QuillConfigurations(
controller: _controller,
sharedConfigurations: const QuillSharedConfigurations(),
),
child: Column(
children: [
const QuillToolbar(),
Expanded(
child: QuillEditor.basic(
configurations: const QuillEditorConfigurations(
readOnly: false, // true for view only mode
),
),
)
],
),
)
```
The `QuillProvider` is an inherited widget that allows you to pass configurations once and use them in the children of it. here we are passing the `_controller` once in the configurations of `QuillProvider` and the `QuillToolbar` and `QuillEditor` will get the `QuillConfigurations` internally, if it doesn't exist you will get an exception.
we also added the `sharedConfigurations` which allow you to configure shared things like the `Local` so you don't have to define them twice, we have removed those from the `QuillToolbar` and `QuillEditor`
2. Regarding The QuillToolbar buttons, we have renamed almost all the buttons, examples:
- `QuillHistory` to `QuillToolbarHistoryButton`
- `IndentButton` to `QuillToolbarIndentButton`
and they usually have two parameters, `controller` and `options`, for example the type for the buttons
- `QuillToolbarHistoryButton` have `QuillToolbarHistoryButtonOptions`
- `QuillToolbarIndentButton` have `QuillToolbarIndentButtonOptions`
- `QuillToolbarClearFormatButton` have `QuillToolbarClearFormatButtonOptions`
All the options have parent `QuillToolbarBaseButtonOptions` which have common things like
```dart
/// By default it will use Icon data from Icons that come from material
/// library for each button, to change this, please pass a different value
/// If there is no Icon in this button then pass null in the child class
final IconData? iconData;
/// To change the icon size pass a different value, by default will be
/// [kDefaultIconSize].
/// This will be used for all the buttons but you can override this
final double globalIconSize;
/// The factor of how much larger the button is in relation to the icon,
/// by default it will be [kIconButtonFactor].
final double globalIconButtonFactor;
/// To do extra logic after pressing the button
final VoidCallback? afterButtonPressed;
/// By default it will use the default tooltip which already localized
final String? tooltip;
/// Use custom theme
final QuillIconTheme? iconTheme;
/// If you want to dispaly a differnet widget based using a builder
final QuillToolbarButtonOptionsChildBuilder<T, I> childBuilder;
/// By default it will be from the one in [QuillProvider]
/// To override it you must pass not null controller
/// if you wish to use the controller in the [childBuilder], please use the
/// one from the extraOptions since it will be not null and will be the one
/// which will be used from the quill toolbar
final QuillController? controller;
```
The `QuillToolbarBaseButtonOptions is`:
```dart
/// The [T] is the option for the button, usually should reference itself
/// it's used in [childBuilder] so the developer can customize this when using it
/// The [I] is an extra option for the button, usually for its state
@immutable
class QuillToolbarBaseButtonOptions<T, I> extends Equatable
```
Example for the clear format button:
```dart
class QuillToolbarClearFormatButtonExtraOptions
extends QuillToolbarBaseButtonExtraOptions {
const QuillToolbarClearFormatButtonExtraOptions({
required super.controller,
required super.context,
required super.onPressed,
});
}
class QuillToolbarClearFormatButtonOptions
extends QuillToolbarBaseButtonOptions<QuillToolbarClearFormatButtonOptions,
QuillToolbarClearFormatButtonExtraOptions> {
const QuillToolbarClearFormatButtonOptions({
super.iconData,
super.afterButtonPressed,
super.childBuilder,
super.controller,
super.iconTheme,
super.tooltip,
this.iconSize,
});
final double? iconSize;
}
```
The base for extra options:
```dart
@immutable
class QuillToolbarBaseButtonExtraOptions extends Equatable {
const QuillToolbarBaseButtonExtraOptions({
required this.controller,
required this.context,
required this.onPressed,
});
/// If you need the not null controller for some usage in the [childBuilder]
/// Then please use this instead of the one in the [options]
final QuillController controller;
/// If the child builder you must use this when the widget is tapped or pressed
/// in order to do what it expected to do
final VoidCallback? onPressed;
final BuildContext context;
@override
List<Object?> get props => [
controller,
];
}
```
which usually share common things, it also add an extra property which was not exist, which is `childBuilder` which allow to rendering of custom widget based on the state of the button and the options it
```dart
QuillToolbar(
configurations: QuillToolbarConfigurations(
buttonOptions: QuillToolbarButtonOptions(
clearFormat: QuillToolbarClearFormatButtonOptions(
childBuilder: (options, extraOptions) {
return IconButton.filled(
onPressed: extraOptions.onPressed,
icon: const Icon(
CupertinoIcons.clear // or options.iconData
),
);
},
),
),
),
),
```
the `extraOptions` usually contains the state variables and the events that you need to trigger like the `onPressed`, it also has the end context and the controller that will be used
while the `options` has the custom controller for each button and it's nullable because there could be no custom controller so we will just use the global one
3. The `QuillToolbar` and `QuillToolbar.basic()` factory constructor
since the basic factory constructor has more options than the original `QuillToolbar` which doesn't make much sense, at least to some developers, we have refactored the `QuillToolbar.basic()` to a different widget called the `QuillToolbar` and the `QuillToolbar` has been renamed to `QuillBaseToolbar` which is the base for `QuillToolbar` or any custom toolbar, sure you can create custom toolbar from scratch by just using the `controller` but if you want more support from the library use the `QuillBaseToolbar`
the children widgets of the new `QuillToolbar` and `QuillEditor` access to their configurations by another two inherited widgets
since `QuillToolbar` and `QuillEditor` take the configuration class and provide them internally using `QuillToolbarProvider` and `QuillEditorProvider`
however the `QuillBaseToolbar` has a little bit different configurations so it has a different provider called `QuillBaseToolbarProvider` and it also already provided by default
But there is one **note**:
> If you are using the toolbar buttons like `QuillToolbarHistoryButton`, `QuillToolbarToggleStyleButton` somewhere like the the custom toolbar (using `QuillBaseToolbar` or any custom widget) then you must provide them with `QuillToolbarProvider` inherited widget, you don't have to do this if you are using the `QuillToolbar` since it will be done for you
>
Example of a custom toolbar:
```dart
QuillProvider(
configurations: QuillConfigurations(
controller: _controller,
sharedConfigurations: const QuillSharedConfigurations(),
),
child: Column(
children: [
QuillToolbarProvider(
toolbarConfigurations: const QuillToolbarConfigurations(),
child: QuillBaseToolbar(
configurations: QuillBaseToolbarConfigurations(
toolbarSize: 15 * 2,
multiRowsDisplay: false,
childrenBuilder: (context) {
final controller = context.requireQuillController; // new extension which is a little bit shorter to access the quill provider then the controller
// there are many options, feel free to explore them all!!
return [
QuillToolbarHistoryButton(
controller: controller,
options: const QuillToolbarHistoryButtonOptions(
isUndo: true),
),
QuillToolbarHistoryButton(
controller: controller,
options: const QuillToolbarHistoryButtonOptions(
isUndo: false),
),
QuillToolbarToggleStyleButton(
attribute: Attribute.bold,
controller: controller,
options: const QuillToolbarToggleStyleButtonOptions(
iconData: Icons.format_bold,
iconSize: 20,
),
),
QuillToolbarToggleStyleButton(
attribute: Attribute.italic,
controller: controller,
options: const QuillToolbarToggleStyleButtonOptions(
iconData: Icons.format_italic,
iconSize: 20,
),
),
QuillToolbarToggleStyleButton(
attribute: Attribute.underline,
controller: controller,
options: const QuillToolbarToggleStyleButtonOptions(
iconData: Icons.format_underline,
iconSize: 20,
),
),
QuillToolbarClearFormatButton(
controller: controller,
options: const QuillToolbarClearFormatButtonOptions(
iconData: Icons.format_clear,
iconSize: 20,
),
),
VerticalDivider(
indent: 12,
endIndent: 12,
color: Colors.grey.shade400,
),
QuillToolbarSelectHeaderStyleButtons(
controller: controller,
options:
const QuillToolbarSelectHeaderStyleButtonsOptions(
iconSize: 20,
),
),
QuillToolbarToggleStyleButton(
attribute: Attribute.ol,
controller: controller,
options: const QuillToolbarToggleStyleButtonOptions(
iconData: Icons.format_list_numbered,
iconSize: 20,
),
),
QuillToolbarToggleStyleButton(
attribute: Attribute.ul,
controller: controller,
options: const QuillToolbarToggleStyleButtonOptions(
iconData: Icons.format_list_bulleted,
iconSize: 20,
),
),
QuillToolbarToggleStyleButton(
attribute: Attribute.blockQuote,
controller: controller,
options: const QuillToolbarToggleStyleButtonOptions(
iconData: Icons.format_quote,
iconSize: 20,
),
),
VerticalDivider(
indent: 12,
endIndent: 12,
color: Colors.grey.shade400,
),
QuillToolbarIndentButton(
controller: controller,
isIncrease: true,
options: const QuillToolbarIndentButtonOptions(
iconData: Icons.format_indent_increase,
iconSize: 20,
)),
QuillToolbarIndentButton(
controller: controller,
isIncrease: false,
options: const QuillToolbarIndentButtonOptions(
iconData: Icons.format_indent_decrease,
iconSize: 20,
),
),
];
},
),
),
),
Expanded(
child: QuillEditor.basic(
configurations: const QuillEditorConfigurations(
readOnly: false,
placeholder: 'Write your notes',
padding: EdgeInsets.all(16),
),
),
)
],
),
)
```
4. The `QuillEditor` and `QuillEditor.basic()`
since the `QuillEditor.basic()` is a lighter version than the original `QuillEditor` since it has fewer required configurations we didn't change much, other than the configuration class, but we must inform you if you plan on sending pull request or you are a maintainer and when you add new property or change anything in `QuillEditorConfigurations` please regenerate the `copyWith` (using IDE extension or plugin) otherwise the `QuilEditor.basic()` will not apply some configurations
we have disabled the line numbers in the code block by default, you can enable them again using the following:
```dart
QuillEditor.basic(
configurations: const QuillEditorConfigurations(
elementOptions: QuillEditorElementOptions(
codeBlock: QuillEditorCodeBlockElementOptions(
enableLineNumbers: true,
),
),
),
)
```
5. `QuillCustomButton`:
We have renamed the property `icon` to `iconData` to indicate it an icon data and not an icon widget
```dart
QuillCustomButton(
iconData: Icons.ac_unit,
onTap: () {
debugPrint('snowflake');
}
),
```
6. Using custom local for both `QuillEditor` and `QuillToolbar`
We have added shared configurations property for shared things
```dart
QuillProvider(
configurations: QuillConfigurations(
controller: _controller,
sharedConfigurations: const QuillSharedConfigurations(
locale: Locale('fr'),
),
),
child: Column(
children: [
const QuillToolbar(
configurations: QuillToolbarConfigurations(),
),
Expanded(
child: QuillEditor.basic(
configurations: const QuillEditorConfigurations(),
),
)
],
),
)
```
7. Image size for all platforms
We have added new properties `width`, `height`, `margin`, `alignment` for all platforms other than mobile and web for the images for example
```dart
{
"insert": {
"image": "https://user-images.githubusercontent.com/122956/72955931-ccc07900-3d52-11ea-89b1-d468a6e2aa2b.png"
},
"attributes":{
"style":"width: 50; height: 50; margin: 10; alignment: topLeft"
}
}
```
8. Other Improvements
You don't need anything to get this done, we have used const more when possible, removed unused events, flutter best practices, converted to stateless widgets when possible, and used better ways to listen for changes example:
instead of
```dart
MediaQuery.of(context).size;
```
we will use
```dart
MediaQuery.sizeOf(context);
```
We also minimized the number of rebuilds using more efficient logic and there is more.
9. More options
We have added more options in the extension package, for all the buttons, configurations, animations, enable and disable things
If you are facing any issues or questions feel free to ask us on GitHub issues

@ -0,0 +1,83 @@
1. Removing the `QuillProvider`
We got a lot of feedbacks about `QuillProvider`, while the provider help removing duplicate lines for simple usage, for more advance usage it become very messy
So from now on we will use providers for the `QuillToolbar` and `QuillEditor` only internally, you don't need it anymore
Instead you will need to pass the configurations directly in the `QuillToolbar` and `QuillEditor`
**Old code**:
```dart
QuillProvider(
configurations: QuillConfigurations(
controller: _controller,
sharedConfigurations: const QuillSharedConfigurations(),
),
child: Column(
children: [
const QuillToolbar(),
Expanded(
child: QuillEditor.basic(
configurations: const QuillEditorConfigurations(
readOnly: false, // true for view only mode
),
),
)
],
),
)
```
**New code**:
```dart
Column(
children: [
QuillToolbar.simple(
QuillSimpleToolbarConfigurations(controller: _controller)),
Expanded(
child: QuillEditor.basic(
configurations: QuillEditorConfigurations(controller: _controller),
),
)
],
)
```
2. Refactoring the Base Toolbar
From now on, the `QuillToolbar` will be a widget that only provides the things that the buttons needs like localizations and `QuillToolbarProvider`
So you can define your own toolbar from scratch just like in Quill JS
The `QuillToolbar` is now accepting only `child` with no configurations so you can customize everything you wants, the `QuillToolbar.simple()` or `QuillSimpleToolbar` implements a simple toolbar that is based on `QuillToolbar`, you are free to use it but it just an example and not standard
1. Source Code Structure
Completly changed the way how the source code structured to more basic and simple way, organize folders and file names, if you use the library
from `flutter_quill_extensions.dart` then there is nothing you need to do, but if you are using any other import then you need to re-imports
4. Change the version system
For [more details](https://github.com/singerdmx/flutter-quill/discussions/1560)
5. Dependencies changes
1. Add `gal_linux` in `flutter_quill_extensions`
2. Replace `pasteboard` with `rich_cliboard`
3. Remove `flutter_animate`
6. Optional options for the buttons
All the buttons from now on, have optional options parameter
7. Improve Flutter Quill Extensions
Bug fixes and new features, the extensions package keep getting better thanks to the community.
8. Migrate to Material 3
We have migrated all of the buttons to material 3, removed a lot of old parameters, if you want to customize one or all the buttons to replacing it with completly different widget with the same state use the `base` in the button options for all or the button name for one
We have also replaced the header style buttons with one dropdown button as a default, replaced the alignment buttons with less code and a lot more

@ -29,6 +29,10 @@ This is a todo list page that added recently and will be updated soon.
- Extract the shared properties between `QuillRawEditorConfigurations` and `QuillEditorConfigurations`
- The todo in the this [commit](https://github.com/singerdmx/flutter-quill/commit/79597ea6425357795c0663588ac079665241f23a) needs to be checked
- use `maybeOf` and of instead `ofNotNull` in the providers to follow flutter offical convenstion, completly rework the providers and update the build context extensions
- Add line through to the text when the check point checked is true
- Change the color of the numbers and dots in ol/ul to match the ones in the item list
- Fix the bugs of the font family and font size
- Try to update Quill Html Converter
### Bugs
@ -39,12 +43,7 @@ Please go to the [issues](https://github.com/singerdmx/flutter-quill/issues)
## Flutter Quill Extensions
### Features
- 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.

@ -56,7 +56,7 @@ flutter gen-l10n
or:
```
./scripts/regenerate-translations.sh
./scripts/regenerate_translations.sh
```

@ -24,7 +24,7 @@ if (flutterVersionName == null) {
android {
namespace "com.example.example"
compileSdk flutter.compileSdkVersion
compileSdkVersion flutter.compileSdkVersion
ndkVersion flutter.ndkVersion
compileOptions {

@ -1,10 +1,11 @@
<manifest xmlns:tools="http://schemas.android.com/tools"
xmlns:android="http://schemas.android.com/apk/res/android">
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
<uses-permission
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="32"
tools:ignore="ScopedStorage" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
@ -43,7 +44,7 @@
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<!-- For `image_cropper` plugin -->
<!-- For `image_cropper` plugin https://pub.dev/packages/image_cropper -->
<activity
android:name="com.yalantis.ucrop.UCropActivity"
android:screenOrientation="portrait"
@ -54,5 +55,12 @@
<meta-data
android:name="flutterEmbedding"
android:value="2" />
<!-- For `super_clipboard` plugin https://pub.dev/packages/super_clipboard -->
<provider
android:name="com.superlist.super_native_extensions.DataProvider"
android:authorities="com.example.example.SuperClipboardDataProvider"
android:exported="true"
android:grantUriPermissions="true" />
</application>
</manifest>

@ -8,7 +8,7 @@ buildscript {
}
dependencies {
classpath 'com.android.tools.build:gradle:8.1.4'
classpath 'com.android.tools.build:gradle:8.2.0'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}

@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-all.zip

@ -82,7 +82,7 @@ class MyQuillEditor extends StatelessWidget {
'Error while loading an image: ${error.toString()}',
);
},
imageProviderBuilder: (imageUrl) {
imageProviderBuilder: (context, imageUrl) {
// cached_network_image is supported
// only for Android, iOS and web
@ -99,6 +99,7 @@ class MyQuillEditor extends StatelessWidget {
return getImageProviderByImageSource(
imageUrl,
imageProviderBuilder: null,
context: context,
assetsPrefix: QuillSharedExtensionsConfigurations.get(
context: context)
.assetsPrefix,

@ -10,16 +10,17 @@ import 'package:path/path.dart' as path;
import 'package:path_provider/path_provider.dart'
show getApplicationDocumentsDirectory;
import '../extensions/scaffold_messenger.dart';
import '../settings/cubit/settings_cubit.dart';
import 'embeds/timestamp_embed.dart';
class MyQuillToolbar extends StatelessWidget {
const MyQuillToolbar({
required this.controller,
required this.focusNode,
super.key,
});
final QuillController controller;
final FocusNode focusNode;
Future<void> onImageInsertWithCropping(
@ -65,7 +66,7 @@ class MyQuillToolbar extends StatelessWidget {
}
Future<void> onImageInsert(String image, QuillController controller) async {
if (isWeb()) {
if (isWeb() || isHttpBasedUrl(image)) {
controller.insertImageBlock(imageSource: image);
return;
}
@ -98,132 +99,114 @@ class MyQuillToolbar extends StatelessWidget {
if (state.useCustomQuillToolbar) {
// For more info
// https://github.com/singerdmx/flutter-quill/blob/master/doc/custom_toolbar.md
return QuillBaseToolbar(
configurations: QuillBaseToolbarConfigurations(
toolbarSize: 15 * 2,
multiRowsDisplay: false,
buttonOptions: const QuillToolbarButtonOptions(
return QuillToolbar(
configurations: const QuillToolbarConfigurations(
buttonOptions: QuillToolbarButtonOptions(
base: QuillToolbarBaseButtonOptions(
globalIconSize: 30,
globalIconSize: 20,
globalIconButtonFactor: 1.4,
),
),
childrenBuilder: (context) {
final controller = context.requireQuillController;
return [
QuillToolbarImageButton(
controller: controller,
options: const QuillToolbarImageButtonOptions(),
),
child: SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Row(
children: [
IconButton(
onPressed: () => context
.read<SettingsCubit>()
.updateSettings(
state.copyWith(useCustomQuillToolbar: false)),
icon: const Icon(
Icons.width_normal,
),
),
QuillToolbarHistoryButton(
isUndo: true,
controller: controller,
options:
const QuillToolbarHistoryButtonOptions(isUndo: true),
),
QuillToolbarHistoryButton(
isUndo: false,
controller: controller,
options:
const QuillToolbarHistoryButtonOptions(isUndo: false),
),
QuillToolbarToggleStyleButton(
attribute: Attribute.bold,
options: const QuillToolbarToggleStyleButtonOptions(),
controller: controller,
options: QuillToolbarToggleStyleButtonOptions(
childBuilder: (options, extraOptions) {
if (extraOptions.isToggled) {
return IconButton.filled(
onPressed: extraOptions.onPressed,
icon: Icon(options.iconData),
);
}
return IconButton(
onPressed: extraOptions.onPressed,
icon: Icon(options.iconData),
);
},
),
attribute: Attribute.bold,
),
QuillToolbarToggleStyleButton(
attribute: Attribute.italic,
options: const QuillToolbarToggleStyleButtonOptions(),
controller: controller,
options: const QuillToolbarToggleStyleButtonOptions(
iconData: Icons.format_italic,
),
attribute: Attribute.italic,
),
QuillToolbarToggleStyleButton(
attribute: Attribute.underline,
controller: controller,
options: const QuillToolbarToggleStyleButtonOptions(
iconData: Icons.format_underline,
iconSize: 20,
),
attribute: Attribute.underline,
),
QuillToolbarClearFormatButton(
controller: controller,
options: const QuillToolbarClearFormatButtonOptions(
iconData: Icons.format_clear,
),
const VerticalDivider(),
QuillToolbarImageButton(
controller: controller,
),
VerticalDivider(
indent: 12,
endIndent: 12,
color: Colors.grey.shade400,
QuillToolbarCameraButton(
controller: controller,
),
QuillToolbarSelectHeaderStyleButtons(
QuillToolbarVideoButton(
controller: controller,
options: const QuillToolbarSelectHeaderStyleButtonsOptions(
iconSize: 20,
),
const VerticalDivider(),
QuillToolbarColorButton(
controller: controller,
isBackground: false,
),
QuillToolbarToggleStyleButton(
attribute: Attribute.ol,
QuillToolbarColorButton(
controller: controller,
options: const QuillToolbarToggleStyleButtonOptions(
iconData: Icons.format_list_numbered,
iconSize: 39,
isBackground: true,
),
const VerticalDivider(),
QuillToolbarSelectHeaderStyleButton(
controller: controller,
),
QuillToolbarToggleStyleButton(
attribute: Attribute.ul,
const VerticalDivider(),
QuillToolbarToggleCheckListButton(
controller: controller,
options: const QuillToolbarToggleStyleButtonOptions(
iconData: Icons.format_list_bulleted,
),
QuillToolbarToggleStyleButton(
controller: controller,
attribute: Attribute.ol,
),
QuillToolbarToggleStyleButton(
attribute: Attribute.blockQuote,
controller: controller,
options: const QuillToolbarToggleStyleButtonOptions(
iconData: Icons.format_quote,
iconSize: 15,
attribute: Attribute.ul,
),
QuillToolbarToggleStyleButton(
controller: controller,
attribute: Attribute.inlineCode,
),
VerticalDivider(
indent: 12,
endIndent: 12,
color: Colors.grey.shade400,
QuillToolbarToggleStyleButton(
controller: controller,
attribute: Attribute.blockQuote,
),
QuillToolbarIndentButton(
controller: controller,
isIncrease: true,
options: const QuillToolbarIndentButtonOptions(
iconData: Icons.format_indent_increase,
iconSize: 20,
)),
),
QuillToolbarIndentButton(
controller: controller,
isIncrease: false,
options: const QuillToolbarIndentButtonOptions(
iconData: Icons.format_indent_decrease,
iconSize: 20,
),
const VerticalDivider(),
QuillToolbarLinkStyleButton(controller: controller),
],
),
];
},
),
);
}
return QuillToolbar(
configurations: QuillToolbarConfigurations(
return QuillSimpleToolbar(
configurations: QuillSimpleToolbarConfigurations(
controller: controller,
showAlignmentButtons: true,
buttonOptions: QuillToolbarButtonOptions(
base: QuillToolbarBaseButtonOptions(
@ -235,7 +218,6 @@ class MyQuillToolbar extends StatelessWidget {
QuillToolbarCustomButtonOptions(
icon: const Icon(Icons.add_alarm_rounded),
onPressed: () {
final controller = context.requireQuillController;
controller.document
.insert(controller.selection.extentOffset, '\n');
controller.updateSelection(
@ -279,13 +261,10 @@ class MyQuillToolbar extends StatelessWidget {
},
),
QuillToolbarCustomButtonOptions(
icon: const Icon(Icons.ac_unit),
icon: const Icon(Icons.dashboard_customize),
onPressed: () {
ScaffoldMessenger.of(context)
..clearSnackBars()
..showText(
'Custom button!',
);
context.read<SettingsCubit>().updateSettings(
state.copyWith(useCustomQuillToolbar: true));
},
),
],

@ -4,14 +4,13 @@ import 'package:flutter/material.dart';
import 'package:flutter_quill/flutter_quill.dart';
import 'package:flutter_quill_extensions/flutter_quill_extensions.dart'
show FlutterQuillEmbeds, QuillSharedExtensionsConfigurations;
import 'package:quill_html_converter/quill_html_converter.dart';
import 'package:share_plus/share_plus.dart' show Share;
import '../extensions/scaffold_messenger.dart';
import '../shared/widgets/home_screen_button.dart';
import 'quill_editor.dart';
import 'quill_toolbar.dart';
import 'my_quill_editor.dart';
import 'my_quill_toolbar.dart';
@immutable
class QuillScreenArgs {
@ -46,6 +45,18 @@ class _QuillScreenState extends State<QuillScreen> {
_controller.document = widget.args.document;
}
// Future<void> _init() async {
// final reader = await ClipboardReader.readClipboard();
// if (reader.canProvide(Formats.htmlText)) {
// final html = await reader.readValue(Formats.htmlText);
// if (html == null) {
// return;
// }
// final delta = DeltaHtmlExt.fromHtml(html);
// _controller.document = Document.fromDelta(delta);
// }
// }
@override
void dispose() {
_controller.dispose();
@ -65,7 +76,7 @@ class _QuillScreenState extends State<QuillScreen> {
onPressed: () {
final html = _controller.document.toDelta().toHtml();
_controller.document =
Document.fromDelta(DeltaHtmlExt.fromHtml(html));
Document.fromDelta(QuillController.fromHtml(html));
},
icon: const Icon(Icons.html),
),
@ -100,23 +111,11 @@ class _QuillScreenState extends State<QuillScreen> {
const HomeScreenButton(),
],
),
body: QuillProvider(
configurations: QuillConfigurations(
controller: _controller,
sharedConfigurations: QuillSharedConfigurations(
animationConfigurations: QuillAnimationConfigurations.disableAll(),
extraConfigurations: const {
QuillSharedExtensionsConfigurations.key:
QuillSharedExtensionsConfigurations(
assetsPrefix: 'assets',
),
},
),
),
child: Column(
body: Column(
children: [
if (!_isReadOnly)
MyQuillToolbar(
controller: _controller,
focusNode: _editorFocusNode,
),
Builder(
@ -124,7 +123,23 @@ class _QuillScreenState extends State<QuillScreen> {
return Expanded(
child: MyQuillEditor(
configurations: QuillEditorConfigurations(
sharedConfigurations: _sharedConfigurations,
controller: _controller,
readOnly: _isReadOnly,
customStyles: const DefaultStyles(),
elementOptions: const QuillEditorElementOptions(
codeBlock: QuillEditorCodeBlockElementOptions(
enableLineNumbers: true,
),
// orderedList: QuillEditorOrderedListElementOptions(
// backgroundColor: Colors.amber,
// fontColor: Colors.black,
// ),
// unorderedList: QuillEditorUnOrderedListElementOptions(
// backgroundColor: Colors.green,
// fontColor: Colors.red,
// ),
),
),
scrollController: _editorScrollController,
focusNode: _editorFocusNode,
@ -134,11 +149,22 @@ class _QuillScreenState extends State<QuillScreen> {
),
],
),
),
floatingActionButton: FloatingActionButton(
child: Icon(_isReadOnly ? Icons.lock : Icons.edit),
onPressed: () => setState(() => _isReadOnly = !_isReadOnly),
),
);
}
QuillSharedConfigurations get _sharedConfigurations {
return const QuillSharedConfigurations(
// locale: Locale('en'),
extraConfigurations: {
QuillSharedExtensionsConfigurations.key:
QuillSharedExtensionsConfigurations(
assetsPrefix: 'assets', // Defaults to assets
),
},
);
}
}

@ -5,11 +5,7 @@ final quillImagesSample = [
{'insert': '\n'},
{
'insert': {'image': Assets.images.screenshot1.path},
'attributes': {
'width': '200',
'height': '500',
'style': 'width:500px; height:350px; margin: 20px;'
}
'attributes': {'style': 'width: 40vh; height:350px; margin: 20px;'}
},
{'insert': '\n'},
{'insert': 'Here is a network image: \n'},

@ -0,0 +1,36 @@
import 'package:flutter/material.dart';
import 'package:flutter_quill/flutter_quill.dart';
class SimpleScreen extends StatefulWidget {
const SimpleScreen({super.key});
@override
State<SimpleScreen> createState() => _SimpleScreenState();
}
class _SimpleScreenState extends State<SimpleScreen> {
final _controller = QuillController.basic();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Column(
children: [
QuillToolbar.simple(
configurations:
QuillSimpleToolbarConfigurations(controller: _controller),
),
Expanded(
child: QuillEditor.basic(
configurations: QuillEditorConfigurations(
controller: _controller,
padding: const EdgeInsets.all(16),
),
),
),
],
),
);
}
}

@ -8,7 +8,8 @@
#include <desktop_drop/desktop_drop_plugin.h>
#include <file_selector_linux/file_selector_plugin.h>
#include <pasteboard/pasteboard_plugin.h>
#include <irondash_engine_context/irondash_engine_context_plugin.h>
#include <super_native_extensions/super_native_extensions_plugin.h>
#include <url_launcher_linux/url_launcher_plugin.h>
void fl_register_plugins(FlPluginRegistry* registry) {
@ -18,9 +19,12 @@ void fl_register_plugins(FlPluginRegistry* registry) {
g_autoptr(FlPluginRegistrar) file_selector_linux_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "FileSelectorPlugin");
file_selector_plugin_register_with_registrar(file_selector_linux_registrar);
g_autoptr(FlPluginRegistrar) pasteboard_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "PasteboardPlugin");
pasteboard_plugin_register_with_registrar(pasteboard_registrar);
g_autoptr(FlPluginRegistrar) irondash_engine_context_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "IrondashEngineContextPlugin");
irondash_engine_context_plugin_register_with_registrar(irondash_engine_context_registrar);
g_autoptr(FlPluginRegistrar) super_native_extensions_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "SuperNativeExtensionsPlugin");
super_native_extensions_plugin_register_with_registrar(super_native_extensions_registrar);
g_autoptr(FlPluginRegistrar) url_launcher_linux_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "UrlLauncherPlugin");
url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar);

@ -5,7 +5,8 @@
list(APPEND FLUTTER_PLUGIN_LIST
desktop_drop
file_selector_linux
pasteboard
irondash_engine_context
super_native_extensions
url_launcher_linux
)

@ -9,10 +9,11 @@ import desktop_drop
import device_info_plus
import file_selector_macos
import gal
import pasteboard
import irondash_engine_context
import path_provider_foundation
import share_plus
import sqflite
import super_native_extensions
import url_launcher_macos
import video_player_avfoundation
@ -21,10 +22,11 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin"))
FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin"))
GalPlugin.register(with: registry.registrar(forPlugin: "GalPlugin"))
PasteboardPlugin.register(with: registry.registrar(forPlugin: "PasteboardPlugin"))
IrondashEngineContextPlugin.register(with: registry.registrar(forPlugin: "IrondashEngineContextPlugin"))
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
SharePlusMacosPlugin.register(with: registry.registrar(forPlugin: "SharePlusMacosPlugin"))
SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin"))
SuperNativeExtensionsPlugin.register(with: registry.registrar(forPlugin: "SuperNativeExtensionsPlugin"))
UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin"))
FVPVideoPlayerPlugin.register(with: registry.registrar(forPlugin: "FVPVideoPlayerPlugin"))
}

@ -12,7 +12,7 @@ PODS:
- gal (1.0.0):
- Flutter
- FlutterMacOS
- pasteboard (0.0.1):
- irondash_engine_context (0.0.1):
- FlutterMacOS
- path_provider_foundation (0.0.1):
- Flutter
@ -22,6 +22,8 @@ PODS:
- sqflite (0.0.2):
- FlutterMacOS
- FMDB (>= 2.7.5)
- super_native_extensions (0.0.1):
- FlutterMacOS
- url_launcher_macos (0.0.1):
- FlutterMacOS
- video_player_avfoundation (0.0.1):
@ -34,10 +36,11 @@ DEPENDENCIES:
- file_selector_macos (from `Flutter/ephemeral/.symlinks/plugins/file_selector_macos/macos`)
- FlutterMacOS (from `Flutter/ephemeral`)
- gal (from `Flutter/ephemeral/.symlinks/plugins/gal/darwin`)
- pasteboard (from `Flutter/ephemeral/.symlinks/plugins/pasteboard/macos`)
- irondash_engine_context (from `Flutter/ephemeral/.symlinks/plugins/irondash_engine_context/macos`)
- path_provider_foundation (from `Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin`)
- share_plus (from `Flutter/ephemeral/.symlinks/plugins/share_plus/macos`)
- sqflite (from `Flutter/ephemeral/.symlinks/plugins/sqflite/macos`)
- super_native_extensions (from `Flutter/ephemeral/.symlinks/plugins/super_native_extensions/macos`)
- url_launcher_macos (from `Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos`)
- video_player_avfoundation (from `Flutter/ephemeral/.symlinks/plugins/video_player_avfoundation/darwin`)
@ -56,14 +59,16 @@ EXTERNAL SOURCES:
:path: Flutter/ephemeral
gal:
:path: Flutter/ephemeral/.symlinks/plugins/gal/darwin
pasteboard:
:path: Flutter/ephemeral/.symlinks/plugins/pasteboard/macos
irondash_engine_context:
:path: Flutter/ephemeral/.symlinks/plugins/irondash_engine_context/macos
path_provider_foundation:
:path: Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin
share_plus:
:path: Flutter/ephemeral/.symlinks/plugins/share_plus/macos
sqflite:
:path: Flutter/ephemeral/.symlinks/plugins/sqflite/macos
super_native_extensions:
:path: Flutter/ephemeral/.symlinks/plugins/super_native_extensions/macos
url_launcher_macos:
:path: Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos
video_player_avfoundation:
@ -76,10 +81,11 @@ SPEC CHECKSUMS:
FlutterMacOS: 8f6f14fa908a6fb3fba0cd85dbd81ec4b251fb24
FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a
gal: 61e868295d28fe67ffa297fae6dacebf56fd53e1
pasteboard: 9b69dba6fedbb04866be632205d532fe2f6b1d99
irondash_engine_context: da62996ee25616d2f01bbeb85dc115d813359478
path_provider_foundation: 29f094ae23ebbca9d3d0cec13889cd9060c0e943
share_plus: 76dd39142738f7a68dd57b05093b5e8193f220f7
sqflite: a5789cceda41d54d23f31d6de539d65bb14100ea
super_native_extensions: 85efee3a7495b46b04befcfc86ed12069264ebf3
url_launcher_macos: d2691c7dd33ed713bf3544850a623080ec693d95
video_player_avfoundation: e9e6f9cae7d7a6d9b43519b0aab382bca60fcfd1

@ -13,8 +13,8 @@ dependencies:
cupertino_icons: ^1.0.6
# Flutter Quill Packages
flutter_quill: ^8.6.2
flutter_quill_extensions: ^0.7.0
flutter_quill: ^8.6.4
flutter_quill_extensions: ^0.7.2
flutter_quill_test: ^0.0.5
quill_html_converter: ^0.0.1-experimental.1
@ -24,11 +24,6 @@ dependencies:
cross_file: ^0.3.3+6
cached_network_image: ^3.3.0
gal_linux:
git:
url: https://github.com/freshtechtips/gal-linux.git
ref: main
# Bloc libraries
bloc: ^8.1.2
flutter_bloc: ^8.1.3
@ -49,6 +44,7 @@ dependencies:
file_picker: ^6.1.1
# For sharing text
share_plus: ^7.2.1
super_clipboard: ^0.7.3
dependency_overrides:
flutter_quill:
@ -60,11 +56,6 @@ dependency_overrides:
quill_html_converter:
path: ../packages/quill_html_converter
gal:
git:
url: https://github.com/natsuk4ze/gal.git
ref: plugin_platform_interface
dev_dependencies:
flutter_test:

@ -9,8 +9,9 @@
#include <desktop_drop/desktop_drop_plugin.h>
#include <file_selector_windows/file_selector_windows.h>
#include <gal/gal_plugin_c_api.h>
#include <pasteboard/pasteboard_plugin.h>
#include <irondash_engine_context/irondash_engine_context_plugin_c_api.h>
#include <share_plus/share_plus_windows_plugin_c_api.h>
#include <super_native_extensions/super_native_extensions_plugin_c_api.h>
#include <url_launcher_windows/url_launcher_windows.h>
void RegisterPlugins(flutter::PluginRegistry* registry) {
@ -20,10 +21,12 @@ void RegisterPlugins(flutter::PluginRegistry* registry) {
registry->GetRegistrarForPlugin("FileSelectorWindows"));
GalPluginCApiRegisterWithRegistrar(
registry->GetRegistrarForPlugin("GalPluginCApi"));
PasteboardPluginRegisterWithRegistrar(
registry->GetRegistrarForPlugin("PasteboardPlugin"));
IrondashEngineContextPluginCApiRegisterWithRegistrar(
registry->GetRegistrarForPlugin("IrondashEngineContextPluginCApi"));
SharePlusWindowsPluginCApiRegisterWithRegistrar(
registry->GetRegistrarForPlugin("SharePlusWindowsPluginCApi"));
SuperNativeExtensionsPluginCApiRegisterWithRegistrar(
registry->GetRegistrarForPlugin("SuperNativeExtensionsPluginCApi"));
UrlLauncherWindowsRegisterWithRegistrar(
registry->GetRegistrarForPlugin("UrlLauncherWindows"));
}

@ -6,8 +6,9 @@ list(APPEND FLUTTER_PLUGIN_LIST
desktop_drop
file_selector_windows
gal
pasteboard
irondash_engine_context
share_plus
super_native_extensions
url_launcher_windows
)

File diff suppressed because it is too large Load Diff

@ -16,6 +16,7 @@ to support embedding widgets like images, formulas, videos, and more.
- [Embed Blocks](#embed-blocks)
- [Element properties](#element-properties)
- [Custom Element properties](#custom-element-properties)
- [Image Assets](#image-assets)
- [Drag and drop feature](#drag-and-drop-feature)
- [Features](#features)
- [Contributing](#contributing)
@ -52,8 +53,7 @@ dependencies:
>
> 1. We are using the [`gal`](https://github.com/natsuk4ze/) plugin to save images.
> For this to work, you need to add the appropriate permissions
> to your `Info.plist` and `AndroidManifest.xml` files.
> For this to work, you need to add the appropriate configurations
> See <https://github.com/natsuk4ze/gal#-get-started> to add the needed lines.
>
> 2. We also use [`image_picker`](https://pub.dev/packages/image_picker) plugin for picking images so please make sure to follow the instructions
@ -165,6 +165,28 @@ Define flutterAlignment` as follows:
This works for all platforms except Web
### Image Assets
If you want to use image assets in the Quill Editor, you need to make sure your assets folder is `assets` otherwise:
```dart
QuillEditor.basic(
configurations: const QuillEditorConfigurations(
// ...
sharedConfigurations: QuillSharedConfigurations(
extraConfigurations: {
QuillSharedExtensionsConfigurations.key:
QuillSharedExtensionsConfigurations(
assetsPrefix: 'your-assets-folder-name', // Defaults to `assets`
),
},
),
),
);
```
This info is needed by the package to check if it asset image to use the `AssetImage` provider
### Drag and drop feature
Currently, the drag-and-drop feature is not officially supported, but you can achieve this very easily in the following steps:

@ -6,7 +6,7 @@ import '../../../models/config/toolbar/buttons/formula.dart';
class QuillToolbarFormulaButton extends StatelessWidget {
const QuillToolbarFormulaButton({
required this.controller,
required this.options,
this.options = const QuillToolbarFormulaButtonOptions(),
super.key,
});
@ -71,14 +71,11 @@ class QuillToolbarFormulaButton extends StatelessWidget {
options.childBuilder ?? baseButtonExtraOptions(context).childBuilder;
final iconColor = iconTheme?.iconUnselectedColor ?? theme.iconTheme.color;
final iconFillColor = iconTheme?.iconUnselectedFillColor ??
(options.fillColor ?? theme.canvasColor);
if (childBuilder != null) {
return childBuilder(
QuillToolbarFormulaButtonOptions(
afterButtonPressed: _afterButtonPressed(context),
fillColor: iconFillColor,
iconData: iconData,
iconSize: iconSize,
iconButtonFactor: iconButtonFactor,
@ -94,14 +91,10 @@ class QuillToolbarFormulaButton extends StatelessWidget {
}
return QuillToolbarIconButton(
icon: Icon(iconData, size: iconSize, color: iconColor),
icon: Icon(iconData, size: iconSize * iconButtonFactor, color: iconColor),
tooltip: tooltip,
highlightElevation: 0,
hoverElevation: 0,
size: iconSize * 1.77,
fillColor: iconFillColor,
borderRadius: iconTheme?.borderRadius ?? 2,
onPressed: () => _sharedOnPressed(context),
isFilled: false,
);
}

@ -1,4 +1,3 @@
import 'package:flutter/foundation.dart' show kIsWeb;
import 'package:flutter/material.dart';
import 'package:flutter_quill/flutter_quill.dart' hide OptionalSize;
import 'package:flutter_quill/translations.dart';
@ -30,15 +29,19 @@ class QuillEditorImageEmbedBuilder extends EmbedBuilder {
bool inline,
TextStyle textStyle,
) {
assert(!kIsWeb, 'Please provide image EmbedBuilder for Web');
// assert(!kIsWeb, 'Please provide image EmbedBuilder for Web');
final imageSource = standardizeImageUrl(node.value.data);
final ((imageSize), margin, alignment) = getElementAttributes(node);
final ((imageSize), margin, alignment) = getElementAttributes(
node,
context,
);
final width = imageSize.width;
final height = imageSize.height;
final image = getImageWidgetByImageSource(
context: context,
imageSource,
imageProviderBuilder: configurations.imageProviderBuilder,
imageErrorWidgetBuilder: configurations.imageErrorWidgetBuilder,
@ -56,9 +59,7 @@ class QuillEditorImageEmbedBuilder extends EmbedBuilder {
onTap: configurations.onImageClicked ??
() => showDialog(
context: context,
builder: (_) => QuillProvider.value(
value: context.requireQuillProvider,
child: FlutterQuillLocalizationsWidget(
builder: (_) => FlutterQuillLocalizationsWidget(
child: ImageOptionsMenu(
controller: controller,
configurations: configurations,
@ -69,7 +70,6 @@ class QuillEditorImageEmbedBuilder extends EmbedBuilder {
),
),
),
),
child: Builder(
builder: (context) {
if (margin != null) {

@ -4,7 +4,7 @@ import 'package:flutter/widgets.dart' show BuildContext;
import 'package:flutter_quill/flutter_quill.dart';
import 'package:meta/meta.dart' show immutable;
import '../../../extensions/controller.dart';
import '../../../extensions/controller_ext.dart';
import '../../../services/image_picker/s_image_picker.dart';
/// When request picking an image, for example when the image button toolbar
@ -76,6 +76,7 @@ typedef ImageEmbedBuilderOnRemovedCallback = Future<void> Function(
);
typedef ImageEmbedBuilderProviderBuilder = ImageProvider Function(
BuildContext context,
String imageUrl,
);

@ -1,14 +1,10 @@
import 'package:flutter/cupertino.dart' show showCupertinoModalPopup;
import 'package:flutter/foundation.dart' show kIsWeb;
import 'package:flutter/material.dart';
import 'package:flutter_quill/flutter_quill.dart'
show
ImageUrl,
QuillController,
QuillProvider,
QuillProviderExt,
StyleAttribute,
getEmbedNode;
show ImageUrl, QuillController, StyleAttribute, getEmbedNode;
import 'package:flutter_quill/translations.dart';
import 'package:super_clipboard/super_clipboard.dart';
import '../../../models/config/editor/image/image.dart';
import '../../../models/config/shared_configurations.dart';
@ -55,9 +51,7 @@ class ImageOptionsMenu extends StatelessWidget {
context: context,
builder: (modalContext) {
final screenSize = MediaQuery.sizeOf(modalContext);
return QuillProvider.value(
value: context.requireQuillProvider,
child: FlutterQuillLocalizationsWidget(
return FlutterQuillLocalizationsWidget(
child: ImageResizer(
onImageResize: (width, height) {
final res = getEmbedNode(
@ -83,7 +77,6 @@ class ImageOptionsMenu extends StatelessWidget {
maxWidth: screenSize.width,
maxHeight: screenSize.height,
),
),
);
},
);
@ -96,15 +89,17 @@ class ImageOptionsMenu extends StatelessWidget {
final navigator = Navigator.of(context);
final imageNode =
getEmbedNode(controller, controller.selection.start).value;
final imageUrl = imageNode.value.data;
final image = imageNode.value.data;
controller.copiedImageUrl = ImageUrl(
imageUrl,
image,
getImageStyleString(controller),
);
// TODO: Implement the copy image
// await Clipboard.setData(
// ClipboardData(),
// );
final data = await convertImageToUint8List(image);
if (data != null) {
final item = DataWriterItem()..add(Formats.png(data));
await ClipboardWriter.instance.write([item]);
}
navigator.pop();
},
),
@ -139,7 +134,7 @@ class ImageOptionsMenu extends StatelessWidget {
await configurations.onImageRemovedCallback.call(imageSource);
},
),
...[
if (!kIsWeb)
ListTile(
leading: const Icon(Icons.save),
title: Text(context.loc.save),
@ -188,8 +183,8 @@ class ImageOptionsMenu extends StatelessWidget {
context,
MaterialPageRoute(
builder: (_) => ImageTapWrapper(
assetsPrefix: QuillSharedExtensionsConfigurations.get(
context: context)
assetsPrefix:
QuillSharedExtensionsConfigurations.get(context: context)
.assetsPrefix,
imageUrl: imageSource,
configurations: configurations,
@ -198,7 +193,6 @@ class ImageOptionsMenu extends StatelessWidget {
),
),
],
],
),
);
}

@ -14,7 +14,7 @@ import 'select_image_source.dart';
class QuillToolbarImageButton extends StatelessWidget {
const QuillToolbarImageButton({
required this.controller,
required this.options,
this.options = const QuillToolbarImageButtonOptions(),
super.key,
});
@ -101,21 +101,15 @@ class QuillToolbarImageButton extends StatelessWidget {
final iconTheme = _iconTheme(context);
final iconColor = iconTheme?.iconUnselectedColor ?? theme.iconTheme.color;
final iconFillColor = iconTheme?.iconUnselectedFillColor ??
(options.fillColor ?? theme.canvasColor);
return QuillToolbarIconButton(
icon: Icon(
iconData,
size: iconSize,
size: iconButtonFactor * iconSize,
color: iconColor,
),
tooltip: tooltip,
highlightElevation: 0,
hoverElevation: 0,
size: iconSize * 1.77,
fillColor: iconFillColor,
borderRadius: iconTheme?.borderRadius ?? 2,
isFilled: false,
onPressed: () => _sharedOnPressed(context),
);
}
@ -172,16 +166,13 @@ class QuillToolbarImageButton extends StatelessWidget {
Future<String?> _typeLink(BuildContext context) async {
final value = await showDialog<String>(
context: context,
builder: (_) => QuillProvider.value(
value: context.requireQuillProvider,
child: FlutterQuillLocalizationsWidget(
builder: (_) => FlutterQuillLocalizationsWidget(
child: TypeLinkDialog(
dialogTheme: options.dialogTheme,
linkRegExp: options.linkRegExp,
linkType: LinkType.image,
),
),
),
);
return value;
}

@ -1,6 +1,5 @@
import 'package:flutter/material.dart';
import 'package:flutter_quill/extensions.dart' show isDesktop;
import 'package:flutter_quill/flutter_quill.dart';
import 'package:flutter_quill/translations.dart';
import '../editor/image_embed_types.dart';
@ -55,12 +54,9 @@ Future<InsertImageSource?> showSelectImageSourceDialog({
showDragHandle: true,
context: context,
constraints: const BoxConstraints(maxWidth: 640),
builder: (_) => QuillProvider.value(
value: context.requireQuillProvider,
child: const FlutterQuillLocalizationsWidget(
builder: (_) => const FlutterQuillLocalizationsWidget(
child: SelectImageSourceDialog(),
),
),
);
return imageSource;
}

@ -3,7 +3,7 @@ import 'package:flutter_quill/flutter_quill.dart'
show
QuillController,
QuillIconTheme,
QuillProviderExt,
QuillSimpleToolbarExt,
QuillToolbarBaseButtonOptions,
QuillToolbarIconButton;
import 'package:flutter_quill/translations.dart';
@ -17,7 +17,7 @@ import 'select_camera_action.dart';
class QuillToolbarCameraButton extends StatelessWidget {
const QuillToolbarCameraButton({
required this.controller,
required this.options,
this.options = const QuillToolbarCameraButtonOptions(),
super.key,
});
@ -30,6 +30,13 @@ class QuillToolbarCameraButton extends StatelessWidget {
return iconSize ?? baseFontSize;
}
double _iconButtonFactor(BuildContext context) {
final baseIconFactor =
baseButtonExtraOptions(context).globalIconButtonFactor;
final iconButtonFactor = options.iconButtonFactor;
return iconButtonFactor ?? baseIconFactor;
}
VoidCallback? _afterButtonPressed(BuildContext context) {
return options.afterButtonPressed ??
baseButtonExtraOptions(context).afterButtonPressed;
@ -69,6 +76,7 @@ class QuillToolbarCameraButton extends StatelessWidget {
final tooltip = _tooltip(context);
final iconSize = _iconSize(context);
final iconData = _iconData(context);
final iconButtonFactor = _iconButtonFactor(context);
final childBuilder =
options.childBuilder ?? baseButtonExtraOptions(context).childBuilder;
@ -80,7 +88,7 @@ class QuillToolbarCameraButton extends StatelessWidget {
iconData: options.iconData,
fillColor: options.fillColor,
iconSize: options.iconSize,
iconButtonFactor: options.iconButtonFactor,
iconButtonFactor: iconButtonFactor,
iconTheme: options.iconTheme,
tooltip: options.tooltip,
cameraConfigurations: options.cameraConfigurations,
@ -96,17 +104,11 @@ class QuillToolbarCameraButton extends StatelessWidget {
final theme = Theme.of(context);
final iconColor = iconTheme?.iconUnselectedColor ?? theme.iconTheme.color;
final iconFillColor = iconTheme?.iconUnselectedFillColor ??
(options.fillColor ?? theme.canvasColor);
return QuillToolbarIconButton(
icon: Icon(iconData, size: iconSize, color: iconColor),
icon: Icon(iconData, size: iconButtonFactor * iconSize, color: iconColor),
tooltip: tooltip,
highlightElevation: 0,
hoverElevation: 0,
size: iconSize * 1.77,
fillColor: iconFillColor,
borderRadius: iconTheme?.borderRadius ?? 2,
isFilled: false,
// isDesktop(supportWeb: false) ? null :
onPressed: () => _sharedOnPressed(context),
);
@ -118,9 +120,8 @@ class QuillToolbarCameraButton extends StatelessWidget {
if (customCallback != null) {
return await customCallback(context);
}
final cameraAction = await showDialog<CameraAction>(
final cameraAction = await showSelectCameraActionDialog(
context: context,
builder: (ctx) => const SelectCameraActionDialog(),
);
return cameraAction;
@ -168,12 +169,5 @@ class QuillToolbarCameraButton extends StatelessWidget {
await options.cameraConfigurations.onImageInsertedCallback
?.call(imageFile.path);
}
// final file = await switch (cameraAction) {
// CameraAction.image =>
// imagePickerService.pickImage(source: ImageSource.camera),
// CameraAction.video =>
// imagePickerService.pickVideo(source: ImageSource.camera),
// };
}
}

@ -1,4 +1,5 @@
import 'package:flutter/material.dart';
import 'package:flutter_quill/extensions.dart';
import 'package:flutter_quill/translations.dart';
import 'camera_types.dart';
@ -8,27 +9,46 @@ class SelectCameraActionDialog extends StatelessWidget {
@override
Widget build(BuildContext context) {
return AlertDialog(
contentPadding: EdgeInsets.zero,
content: Column(
mainAxisSize: MainAxisSize.min,
return SizedBox(
height: 150,
width: double.infinity,
child: SingleChildScrollView(
child: Column(
children: [
TextButton.icon(
icon: const Icon(
Icons.camera,
ListTile(
title: Text(context.loc.photo),
subtitle: Text(
context.loc.takeAPhotoUsingYourCamera,
),
label: Text(context.loc.photo),
onPressed: () => Navigator.pop(context, CameraAction.image),
leading: const Icon(Icons.photo_sharp),
enabled: !isDesktop(supportWeb: false),
onTap: () => Navigator.of(context).pop(CameraAction.image),
),
TextButton.icon(
icon: const Icon(
Icons.video_call,
ListTile(
title: Text(context.loc.video),
subtitle: Text(
context.loc.recordAVideoUsingYourCamera,
),
leading: const Icon(Icons.camera),
enabled: !isDesktop(supportWeb: false),
onTap: () => Navigator.of(context).pop(CameraAction.video),
),
label: Text(context.loc.video),
onPressed: () => Navigator.pop(context, CameraAction.video),
)
],
),
),
);
}
}
Future<CameraAction?> showSelectCameraActionDialog({
required BuildContext context,
}) async {
final imageSource = await showModalBottomSheet<CameraAction>(
showDragHandle: true,
context: context,
constraints: const BoxConstraints(maxWidth: 640),
builder: (context) => const FlutterQuillLocalizationsWidget(
child: SelectCameraActionDialog()),
);
return imageSource;
}

@ -2,6 +2,8 @@ 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,
@ -28,7 +30,7 @@ class TypeLinkDialog extends StatefulWidget {
class TypeLinkDialogState extends State<TypeLinkDialog> {
late String _link;
late TextEditingController _controller;
late RegExp _linkRegExp;
RegExp? _linkRegExp;
@override
void initState() {
@ -36,15 +38,7 @@ class TypeLinkDialogState extends State<TypeLinkDialog> {
_link = widget.link ?? '';
_controller = TextEditingController(text: _link);
final defaultLinkNonSecureRegExp = RegExp(
r'https?://.*?\.(?:png|jpe?g|gif|bmp|webp|tiff?)',
caseSensitive: false,
); // Not secure
// final defaultLinkRegExp = RegExp(
// r'https://.*?\.(?:png|jpe?g|gif|bmp|webp|tiff?)',
// caseSensitive: false,
// ); // Secure
_linkRegExp = widget.linkRegExp ?? defaultLinkNonSecureRegExp;
_linkRegExp = widget.linkRegExp;
}
@override
@ -102,8 +96,28 @@ class TypeLinkDialogState extends State<TypeLinkDialog> {
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() {
return _link.isNotEmpty && _linkRegExp.hasMatch(_link);
if (_link.isEmpty) {
return false;
}
if (widget.linkType == LinkType.image) {}
return _link.isNotEmpty && linkRegExp.hasMatch(_link);
}
}

@ -20,7 +20,7 @@
// class QuillToolbarMediaButton extends StatelessWidget {
// QuillToolbarMediaButton({
// required this.controller,
// required this.options,
// this.options,
// super.key,
// }) : assert(options.type == QuillMediaType.image,
// 'Video selection is not supported yet');
@ -135,7 +135,7 @@
// tooltip: tooltip,
// highlightElevation: 0,
// hoverElevation: 0,
// size: iconSize * 1.77,
// size: iconSize * iconButtonFactor,
// fillColor: iconFillColor,
// borderRadius: iconTheme?.borderRadius ?? 2,
// onPressed: () => _sharedOnPressed(context),

@ -37,7 +37,10 @@ class QuillEditorVideoEmbedBuilder extends EmbedBuilder {
readOnly: readOnly,
);
}
final ((elementSize), margin, alignment) = getElementAttributes(node);
final ((elementSize), margin, alignment) = getElementAttributes(
node,
context,
);
final width = elementSize.width;
final height = elementSize.height;

@ -52,7 +52,8 @@ Future<InsertVideoSource?> showSelectVideoSourceDialog({
showDragHandle: true,
context: context,
constraints: const BoxConstraints(maxWidth: 640),
builder: (context) => const SelectVideoSourceDialog(),
builder: (context) =>
const FlutterQuillLocalizationsWidget(child: SelectVideoSourceDialog()),
);
return imageSource;
}

@ -13,8 +13,8 @@ import 'select_video_source.dart';
class QuillToolbarVideoButton extends StatelessWidget {
const QuillToolbarVideoButton({
required this.options,
required this.controller,
this.options = const QuillToolbarVideoButtonOptions(),
super.key,
});
@ -28,6 +28,13 @@ class QuillToolbarVideoButton extends StatelessWidget {
return iconSize ?? baseFontSize;
}
double _iconButtonFactor(BuildContext context) {
final baseIconFactor =
baseButtonExtraOptions(context).globalIconButtonFactor;
final iconButtonFactor = options.iconButtonFactor;
return iconButtonFactor ?? baseIconFactor;
}
VoidCallback? _afterButtonPressed(BuildContext context) {
return options.afterButtonPressed ??
baseButtonExtraOptions(context).afterButtonPressed;
@ -67,6 +74,7 @@ class QuillToolbarVideoButton extends StatelessWidget {
final tooltip = _tooltip(context);
final iconSize = _iconSize(context);
final iconButtonFactor = _iconButtonFactor(context);
final iconData = _iconData(context);
final childBuilder =
options.childBuilder ?? baseButtonExtraOptions(context).childBuilder;
@ -83,7 +91,7 @@ class QuillToolbarVideoButton extends StatelessWidget {
dialogTheme: options.dialogTheme,
fillColor: iconFillColor,
iconSize: options.iconSize,
iconButtonFactor: options.iconButtonFactor,
iconButtonFactor: iconButtonFactor,
linkRegExp: options.linkRegExp,
tooltip: options.tooltip,
iconTheme: options.iconTheme,
@ -98,13 +106,9 @@ class QuillToolbarVideoButton extends StatelessWidget {
}
return QuillToolbarIconButton(
icon: Icon(iconData, size: iconSize, color: iconColor),
icon: Icon(iconData, size: iconSize * iconButtonFactor, color: iconColor),
tooltip: tooltip,
highlightElevation: 0,
hoverElevation: 0,
size: iconSize * 1.77,
fillColor: iconFillColor,
borderRadius: iconTheme?.borderRadius ?? 2,
isFilled: false,
onPressed: () => _sharedOnPressed(context),
);
}
@ -165,15 +169,12 @@ class QuillToolbarVideoButton extends StatelessWidget {
Future<String?> _typeLink(BuildContext context) async {
final value = await showDialog<String>(
context: context,
builder: (_) => QuillProvider.value(
value: context.requireQuillProvider,
child: FlutterQuillLocalizationsWidget(
builder: (_) => FlutterQuillLocalizationsWidget(
child: TypeLinkDialog(
dialogTheme: options.dialogTheme,
linkType: LinkType.video,
),
),
),
);
return value;
}

@ -2,7 +2,7 @@ import 'package:flutter/widgets.dart' show BuildContext;
import 'package:flutter_quill/flutter_quill.dart';
import 'package:meta/meta.dart' show immutable;
import '../../extensions/controller.dart';
import '../../extensions/controller_ext.dart';
import '../../services/image_picker/s_image_picker.dart';
/// When request picking an video, for example when the video button toolbar

@ -36,9 +36,10 @@ ImageProvider getImageProviderByImageSource(
String imageSource, {
required ImageEmbedBuilderProviderBuilder? imageProviderBuilder,
required String assetsPrefix,
required BuildContext context,
}) {
if (imageProviderBuilder != null) {
return imageProviderBuilder(imageSource);
return imageProviderBuilder(context, imageSource);
}
if (isImageBase64(imageSource)) {
@ -50,7 +51,6 @@ ImageProvider getImageProviderByImageSource(
}
if (imageSource.startsWith(assetsPrefix)) {
// TODO: This impl could be improved
return AssetImage(imageSource);
}
return FileImage(File(imageSource));
@ -58,6 +58,7 @@ ImageProvider getImageProviderByImageSource(
Image getImageWidgetByImageSource(
String imageSource, {
required BuildContext context,
required ImageEmbedBuilderProviderBuilder? imageProviderBuilder,
required ImageErrorWidgetBuilder? imageErrorWidgetBuilder,
required String assetsPrefix,
@ -67,6 +68,7 @@ Image getImageWidgetByImageSource(
}) {
return Image(
image: getImageProviderByImageSource(
context: context,
imageSource,
imageProviderBuilder: imageProviderBuilder,
assetsPrefix: assetsPrefix,
@ -127,6 +129,7 @@ class ImageTapWrapper extends StatelessWidget {
children: [
PhotoView(
imageProvider: getImageProviderByImageSource(
context: context,
imageUrl,
imageProviderBuilder: configurations.imageProviderBuilder,
assetsPrefix: assetsPrefix,

@ -36,7 +36,7 @@ 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.dart';
export 'extensions/controller_ext.dart';
export 'models/config/editor/image/image.dart';
export 'models/config/editor/image/image_web.dart';
export 'models/config/editor/video/video.dart';
@ -113,8 +113,8 @@ class FlutterQuillEmbeds {
/// videos iframe on the web.
///
static List<EmbedBuilder> editorWebBuilders(
{QuillEditorWebImageEmbedConfigurations? imageEmbedConfigurations =
const QuillEditorWebImageEmbedConfigurations(),
{QuillEditorImageEmbedConfigurations? imageEmbedConfigurations =
const QuillEditorImageEmbedConfigurations(),
QuillEditorWebVideoEmbedConfigurations? videoEmbedConfigurations =
const QuillEditorWebVideoEmbedConfigurations()}) {
if (!kIsWeb) {
@ -125,7 +125,7 @@ class FlutterQuillEmbeds {
}
return [
if (imageEmbedConfigurations != null)
QuillEditorWebImageEmbedBuilder(
QuillEditorImageEmbedBuilder(
configurations: imageEmbedConfigurations,
),
if (videoEmbedConfigurations != null)

@ -5,34 +5,8 @@ import 'package:meta/meta.dart' show immutable;
import '../../services/image_picker/s_image_picker.dart';
import '../../services/image_saver/s_image_saver.dart';
/// Configurations for Flutter Quill Extensions
/// that is shared between the toolbar and editor for the extensions package
///
/// Example on how to setup it:
///
/// ```dart
/// QuillProvider(
/// configurations: QuillConfigurations(
/// sharedConfigurations: const QuillSharedConfigurations(
/// extraConfigurations: {
/// QuillSharedExtensionsConfigurations.key:
/// QuillSharedExtensionsConfigurations(
/// // Feel free to explore it
/// ),
/// },
/// ),
/// controller: _controller,
/// ),
/// child: const Column(
/// children: [
/// // QuillToolbar
/// // QuillEditor
/// // ...
/// ],
// ),
/// )
/// ```
///
/// Configurations for Flutter Editor Extensions
/// shared between toolbar and editor
@immutable
class QuillSharedExtensionsConfigurations {
const QuillSharedExtensionsConfigurations({
@ -47,17 +21,15 @@ class QuillSharedExtensionsConfigurations {
factory QuillSharedExtensionsConfigurations.get({
required BuildContext context,
}) {
final quillSharedExtensionsConfigurations =
context.requireQuillSharedConfigurations.extraConfigurations[key];
if (quillSharedExtensionsConfigurations != null) {
if (quillSharedExtensionsConfigurations
is! QuillSharedExtensionsConfigurations) {
final value = context.quillSharedConfigurations?.extraConfigurations[key];
if (value != null) {
if (value is! QuillSharedExtensionsConfigurations) {
throw ArgumentError(
'The value of key `$key` should be of type '
'QuillSharedExtensionsConfigurations',
'$key',
);
}
return quillSharedExtensionsConfigurations;
return value;
}
return const QuillSharedExtensionsConfigurations();
}
@ -66,8 +38,8 @@ class QuillSharedExtensionsConfigurations {
/// which can be found in the [QuillSharedConfigurations]
/// which lives in the [QuillConfigurations]
///
/// which exists in the [QuillProvider]
static const String key = 'quillSharedExtensionsConfigurations';
/// which exists in the [QuillEditorConfigurations]
static const String key = 'QuillSharedExtensionsConfigurations';
/// Defaults to [ImagePickerService.defaultImpl]
final ImagePickerService? _imagePickerService;

@ -1,3 +1,5 @@
import 'package:flutter/widgets.dart' show BuildContext, MediaQuery;
Map<String, String> parseCssString(String cssString) {
final result = <String, String>{};
final declarations = cssString.split(';');
@ -14,16 +16,71 @@ Map<String, String> parseCssString(String cssString) {
return result;
}
double? parseCssPropertyAsDouble(String value) {
enum _CssUnit {
px('px'),
percentage('%'),
viewportWidth('vw'),
viewportHeight('vh'),
em('em'),
rem('rem'),
invalid('invalid');
const _CssUnit(this.cssName);
final String cssName;
}
double? parseCssPropertyAsDouble(
String value, {
required BuildContext context,
}) {
if (value.trim().isEmpty) {
return null;
}
final list = [
'px',
// '%', 'vw', 'vh', 'em', 'rem'
];
for (final element in list) {
value = value.replaceFirst(element, '');
// Try to parse it in case it's a valid double already
var doubleValue = double.tryParse(value);
if (doubleValue != null) {
return doubleValue;
}
// If not then if it's a css numberic value then we will try to parse it
final unit = _CssUnit.values
.where((element) => value.endsWith(element.cssName))
.firstOrNull;
if (unit == null) {
return null;
}
value = value.replaceFirst(unit.cssName, '');
doubleValue = double.tryParse(value);
if (doubleValue != null) {
switch (unit) {
case _CssUnit.px:
// Do nothing
break;
case _CssUnit.percentage:
// Not supported yet
doubleValue = null;
break;
case _CssUnit.viewportWidth:
doubleValue = (doubleValue / 100) * MediaQuery.sizeOf(context).width;
break;
case _CssUnit.viewportHeight:
doubleValue = (doubleValue / 100) * MediaQuery.sizeOf(context).height;
break;
case _CssUnit.em:
doubleValue = MediaQuery.textScalerOf(context).scale(doubleValue);
break;
case _CssUnit.rem:
// Not fully supported yet
doubleValue = MediaQuery.textScalerOf(context).scale(doubleValue);
break;
case _CssUnit.invalid:
// Ignore
doubleValue = null;
break;
}
}
return double.tryParse(value);
return doubleValue;
}

@ -1,5 +1,5 @@
import 'package:flutter/foundation.dart' show immutable;
import 'package:flutter/widgets.dart' show Alignment;
import 'package:flutter/widgets.dart' show Alignment, BuildContext;
import 'package:flutter_quill/extensions.dart';
import 'package:flutter_quill/flutter_quill.dart' show Attribute, Node;
@ -18,15 +18,20 @@ enum ExtraElementProperties {
Alignment alignment,
) getElementAttributes(
Node node,
BuildContext context,
) {
var elementSize = const ElementSize(null, null);
var elementAlignment = Alignment.center;
double? elementMargin;
final heightValue = parseCssPropertyAsDouble(
node.style.attributes[Attribute.height.key]?.value.toString() ?? '');
node.style.attributes[Attribute.height.key]?.value.toString() ?? '',
context: context,
);
final widthValue = parseCssPropertyAsDouble(
node.style.attributes[Attribute.width.key]?.value.toString() ?? '');
node.style.attributes[Attribute.width.key]?.value.toString() ?? '',
context: context,
);
if (heightValue != null) {
elementSize = elementSize.copyWith(
@ -46,11 +51,14 @@ enum ExtraElementProperties {
final cssAttrs = parseCssString(cssStyle.value.toString());
// todo: This could be improved much better
final cssHeightValue =
parseCssPropertyAsDouble((cssAttrs[Attribute.height.key]) ?? '');
final cssWidthValue =
parseCssPropertyAsDouble((cssAttrs[Attribute.width.key]) ?? '');
final cssHeightValue = parseCssPropertyAsDouble(
(cssAttrs[Attribute.height.key]) ?? '',
context: context,
);
final cssWidthValue = parseCssPropertyAsDouble(
(cssAttrs[Attribute.width.key]) ?? '',
context: context,
);
// cssHeightValue != null && elementSize.height == null
if (cssHeightValue != null) {

@ -0,0 +1,17 @@
RegExp base64RegExp = RegExp(
r'^(?:[A-Za-z0-9+\/]{4})*(?:[A-Za-z0-9+\/]{2}==|[A-Za-z0-9+\/]{3}=|[A-Za-z0-9+\/]{4})$',
);
final imageRegExp = RegExp(
r'https?://.*?\.(?:png|jpe?g|gif|bmp|webp|tiff?)',
caseSensitive: false,
);
final videoRegExp = RegExp(
r'\bhttps?://\S+\.(mp4|mov|avi|mkv|flv|wmv|webm)\b',
caseSensitive: false,
);
final youtubeRegExp = RegExp(
r'^((?:https?:)?\/\/)?((?:www|m)\.)?((?:youtube(-nocookie)?\.com|youtu.be))(\/(?:[\w\-]+\?v=|embed\/|live\/|v\/)?)([\w\-]+)(\S+)?$',
caseSensitive: false,
);

@ -1,16 +1,15 @@
import 'dart:io' show File;
import 'package:flutter/foundation.dart' show immutable;
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';
RegExp _base64 = RegExp(
r'^(?:[A-Za-z0-9+\/]{4})*(?:[A-Za-z0-9+\/]{2}==|[A-Za-z0-9+\/]{3}=|[A-Za-z0-9+\/]{4})$',
);
import 'patterns.dart';
bool isBase64(String str) {
return _base64.hasMatch(str);
return base64RegExp.hasMatch(str);
}
bool isHttpBasedUrl(String url) {
@ -48,6 +47,23 @@ class SaveImageResult {
final SaveImageResultMethod method;
}
Future<Uint8List?> convertImageToUint8List(String image) async {
if (isHttpBasedUrl(image)) {
final response = await http.get(Uri.parse(image));
if (response.statusCode == 200) {
return Uint8List.fromList(response.bodyBytes);
}
return null;
}
// TODO: Add support for all image providers like AssetImage
try {
final file = XFile(image);
return await file.readAsBytes();
} catch (e) {
return null;
}
}
Future<SaveImageResult> saveImage({
required String imageUrl,
required ImageSaverService imageSaverService,

@ -1,6 +1,6 @@
name: flutter_quill_extensions
description: Embed extensions for flutter_quill including image, video, formula and etc.
version: 0.8.0-dev
version: 9.0.0-dev-8
homepage: https://github.com/singerdmx/flutter-quill/tree/master/flutter_quill_extensions/
repository: https://github.com/singerdmx/flutter-quill/tree/master/flutter_quill_extensions/
issue_tracker: https://github.com/singerdmx/flutter-quill/issues/
@ -35,15 +35,17 @@ dependencies:
universal_html: ^2.2.4
cross_file: ^0.3.3+6
flutter_quill: ^8.6.0
flutter_quill: ^9.0.0-dev
photo_view: ^0.14.0
# Plugins
video_player: ^2.8.1
youtube_player_flutter: ^8.1.2
url_launcher: ^6.2.1
super_clipboard: ^0.7.3
gal: ^2.1.3
gal_linux: ^0.0.1-dev-3
image_picker: ^1.0.4
url_launcher: ^6.2.1
dev_dependencies:
flutter_test:

File diff suppressed because it is too large Load Diff

@ -1,6 +1,6 @@
name: flutter_quill_test
description: Test utilities for flutter_quill which includes methods to simplify interacting with the editor in test cases.
version: 0.0.5
version: 9.0.0-dev-8
homepage: https://github.com/singerdmx/flutter-quill/tree/master/flutter_quill_test/
repository: https://github.com/singerdmx/flutter-quill/tree/master/flutter_quill_test/
issue_tracker: https://github.com/singerdmx/flutter-quill/issues/
@ -28,7 +28,7 @@ environment:
dependencies:
flutter:
sdk: flutter
flutter_quill: ^8.2.5
flutter_quill: ^9.0.0-dev-6
flutter_test:
sdk: flutter

@ -1,9 +1,9 @@
library flutter_quill;
export 'src/extensions/quill_provider.dart';
export 'src/extensions/quill_configurations_ext.dart';
export 'src/models/config/quill_configurations.dart';
export 'src/models/config/raw_editor/configurations.dart';
export 'src/models/config/toolbar/base_toolbar_configurations.dart';
export 'src/models/config/raw_editor/raw_editor_configurations.dart';
export 'src/models/config/toolbar/toolbar_configurations.dart';
export 'src/models/documents/attribute.dart';
export 'src/models/documents/document.dart';
export 'src/models/documents/nodes/block.dart';
@ -22,15 +22,17 @@ export 'src/models/structs/vertical_spacing.dart';
export 'src/models/themes/quill_dialog_theme.dart';
export 'src/models/themes/quill_icon_theme.dart';
export 'src/utils/embeds.dart';
export 'src/widgets/controller.dart';
export 'src/widgets/cursor.dart';
export 'src/widgets/default_styles.dart';
export 'src/widgets/editor/editor.dart';
export 'src/widgets/embeds.dart';
export 'src/widgets/link.dart' show LinkActionPickerDelegate, LinkMenuAction;
export 'src/widgets/others/cursor.dart';
export 'src/widgets/others/default_styles.dart';
export 'src/widgets/others/link.dart'
show LinkActionPickerDelegate, LinkMenuAction;
export 'src/widgets/quill/embeds.dart';
export 'src/widgets/quill/quill_controller.dart';
export 'src/widgets/raw_editor/raw_editor.dart';
export 'src/widgets/raw_editor/raw_editor_state.dart';
export 'src/widgets/style_widgets/style_widgets.dart';
export 'src/widgets/toolbar/base_toolbar.dart';
export 'src/widgets/toolbar/toolbar.dart';
export 'src/widgets/toolbar/buttons/select_header_style_button.dart';
export 'src/widgets/toolbar/simple_toolbar.dart';
export 'src/widgets/utils/provider.dart';

@ -0,0 +1,5 @@
library quill_markdown;
export 'src/packages/quill_markdown/delta_to_markdown.dart';
export 'src/packages/quill_markdown/embeddable_table_syntax.dart';
export 'src/packages/quill_markdown/markdown_to_delta.dart';

@ -0,0 +1,93 @@
import 'package:flutter/widgets.dart' show BuildContext;
import '../../flutter_quill.dart';
extension QuillControllerExt on BuildContext {
/// return nullable [QuillController]
QuillController? get quilController {
return quillSimpleToolbarConfigurations?.controller ??
quillEditorConfigurations?.controller;
}
/// return [QuillController] as not null
QuillController get requireQuillController {
return quillSimpleToolbarConfigurations?.controller ??
quillEditorConfigurations?.controller ??
(throw ArgumentError(
'The quill provider is required, you must only call requireQuillController inside the QuillToolbar and QuillEditor'));
}
}
extension QuillSharedExt on BuildContext {
/// return nullable [QuillSharedConfigurations]
QuillSharedConfigurations? get quillSharedConfigurations {
return quillSimpleToolbarConfigurations?.sharedConfigurations ??
quillEditorConfigurations?.sharedConfigurations;
}
}
extension QuillEditorExt on BuildContext {
/// return [QuillEditorConfigurations] as not null
QuillEditorConfigurations get requireQuillEditorConfigurations {
return QuillEditorProvider.of(this).editorConfigurations;
}
/// return nullable [QuillEditorConfigurations]
QuillEditorConfigurations? get quillEditorConfigurations {
return QuillEditorProvider.maybeOf(this)?.editorConfigurations;
}
/// return nullable [QuillToolbarBaseButtonOptions]. Since the quill
/// quill editor block options is in the [QuillEditorProvider] then we need to
/// get the provider widget first and then we will return block options
/// throw exception if [QuillEditorProvider] is not in the widget tree
QuillEditorElementOptions? get quillEditorElementOptions {
return quillEditorConfigurations?.elementOptions;
}
/// return [QuillToolbarBaseButtonOptions] as not null. Since the quill
/// quill editor block options is in the [QuillEditorProvider] then we need to
/// get the provider widget first and then we will return block options
/// don't throw exception if [QuillEditorProvider] is not in the widget tree
QuillEditorElementOptions get requireQuillEditorElementOptions {
return requireQuillEditorConfigurations.elementOptions;
}
}
extension QuillSimpleToolbarExt on BuildContext {
/// return [QuillSimpleToolbarConfigurations] as not null
QuillSimpleToolbarConfigurations get requireQuillSimpleToolbarConfigurations {
return QuillSimpleToolbarProvider.of(this).toolbarConfigurations;
}
/// return nullable [QuillSimpleToolbarConfigurations]
QuillSimpleToolbarConfigurations? get quillSimpleToolbarConfigurations {
return QuillSimpleToolbarProvider.maybeOf(this)?.toolbarConfigurations;
}
/// return nullable [QuillToolbarBaseButtonOptions].
QuillToolbarBaseButtonOptions? get quillToolbarBaseButtonOptions {
return quillSimpleToolbarConfigurations?.buttonOptions.base;
}
/// return [QuillToolbarBaseButtonOptions] as not null.
QuillToolbarBaseButtonOptions get requireQuillToolbarBaseButtonOptions {
return quillSimpleToolbarConfigurations?.buttonOptions.base ??
quillToolbarConfigurations?.buttonOptions.base ??
(throw ArgumentError(
"The buttonOptions is required and it's null because the toolbar configurations is.",
));
}
}
extension QuillToolbarExt on BuildContext {
/// return [QuillToolbarConfigurations] as not null
QuillToolbarConfigurations get requireQuillToolbarConfigurations {
return QuillToolbarProvider.of(this).toolbarConfigurations;
}
/// return nullable [QuillToolbarConfigurations].
QuillToolbarConfigurations? get quillToolbarConfigurations {
return QuillToolbarProvider.maybeOf(this)?.toolbarConfigurations;
}
}

@ -1,11 +1,11 @@
import 'package:flutter/widgets.dart' show BuildContext;
import '../../flutter_quill.dart' show QuillController, QuillProvider;
import 'quill_provider.dart';
import '../../flutter_quill.dart' show QuillController;
import 'quill_configurations_ext.dart';
extension QuillControllerNullableExt on QuillController? {
/// Simple logic to use the current passed controller if not null
/// if null then we will have to use the default one from [QuillProvider]
/// if null then we will have to use the default one
/// using the [context]
QuillController notNull(BuildContext context) {
final controller = this;

@ -1,160 +0,0 @@
import 'package:flutter/widgets.dart' show BuildContext;
import '../../flutter_quill.dart';
// TODO: The comments of this file is outdated and needs to be updated
/// Public shared extension
extension QuillProviderExt on BuildContext {
/// return [QuillProvider] as not null
/// throw exception if it's not in the widget tree
QuillProvider get requireQuillProvider {
return QuillProvider.ofNotNull(this);
}
/// return nullable [QuillProvider]
/// don't throw exception if it's not in the widget tree
/// instead it will be null
QuillProvider? get quillProvider {
return QuillProvider.of(this);
}
/// return nullable [QuillController]
/// since the quill controller is in the [QuillProvider] then we need to get
/// the provider widget first and then we will return the controller
/// don't throw exception if [QuillProvider] is not in the widget tree
/// instead it will be null
QuillController? get quilController {
return quillProvider?.configurations.controller;
}
/// return [QuillController] as not null
/// since the quill controller is in the [QuillProvider] then we need to get
/// the provider widget first and then we will return the controller
/// throw exception if [QuillProvider] is not in the widget tree
QuillController get requireQuillController {
return requireQuillProvider.configurations.controller;
}
/// return [QuillConfigurations] as not null
/// since the quill configurations is in the [QuillProvider] then we need to
/// get the provider widget first and then we will return quill configurations
/// throw exception if [QuillProvider] is not in the widget tree
QuillConfigurations get requireQuillConfigurations {
return requireQuillProvider.configurations;
}
/// return nullable [QuillConfigurations]
/// since the quill configurations is in the [QuillProvider] then we need to
/// get the provider widget first and then we will return quill configurations
/// don't throw exception if [QuillProvider] is not in the widget tree
QuillConfigurations? get quillConfigurations {
return quillProvider?.configurations;
}
/// return [QuillSharedConfigurations] as not null. Since the quill
/// shared configurations is in the [QuillProvider] then we need to get the
/// provider widget first and then we will return shared configurations
/// throw exception if [QuillProvider] is not in the widget tree
QuillSharedConfigurations get requireQuillSharedConfigurations {
return requireQuillConfigurations.sharedConfigurations;
}
/// return nullable [QuillSharedConfigurations] . Since the quill
/// shared configurations is in the [QuillProvider] then we need to get the
/// provider widget first and then we will return shared configurations
/// don't throw exception if [QuillProvider] is not in the widget tree
QuillSharedConfigurations? get quillSharedConfigurations {
return quillConfigurations?.sharedConfigurations;
}
/// return [QuillEditorConfigurations] as not null . Since the quill
/// editor configurations is in the [QuillEditorProvider]
/// then we need to get the
/// provider widget first and then we will return editor configurations
/// throw exception if [QuillProvider] is not in the widget tree
QuillEditorConfigurations get requireQuillEditorConfigurations {
return QuillEditorProvider.ofNotNull(this).editorConfigurations;
}
/// return nullable [QuillEditorConfigurations]. Since the quill
/// editor configurations is in the [QuillEditorProvider]
/// then we need to get the
/// provider widget first and then we will return editor configurations
/// don't throw exception if [QuillProvider] is not in the widget tree
QuillEditorConfigurations? get quillEditorConfigurations {
return QuillEditorProvider.of(this)?.editorConfigurations;
}
/// return [QuillToolbarConfigurations] as not null . Since the quill
/// toolbar configurations is in the [QuillToolbarProvider]
/// then we need to get the
/// provider widget first and then we will return toolbar configurations
/// throw exception if [QuillProvider] is not in the widget tree
QuillToolbarConfigurations get requireQuillToolbarConfigurations {
return QuillToolbarProvider.ofNotNull(this).toolbarConfigurations;
}
/// return nullable [QuillToolbarConfigurations]. Since the quill
/// toolbar configurations is in the [QuillToolbarProvider]
/// then we need to get the
/// provider widget first and then we will return toolbar configurations
/// don't throw exception if [QuillProvider] is not in the widget tree
QuillToolbarConfigurations? get quillToolbarConfigurations {
return QuillToolbarProvider.of(this)?.toolbarConfigurations;
}
/// return [QuillBaseToolbarConfigurations] as not null . Since the quill
/// toolbar configurations is in the [QuillBaseToolbarProvider]
/// then we need to get the
/// provider widget first and then we will return toolbar configurations
/// throw exception if [QuillBaseToolbarProvider] is not in the widget tree
QuillBaseToolbarConfigurations get requireQuillBaseToolbarConfigurations {
return QuillBaseToolbarProvider.ofNotNull(this).toolbarConfigurations;
}
/// return nullable [QuillBaseToolbarConfigurations]. Since the quill
/// toolbar configurations is in the [QuillBaseToolbarProvider]
/// then we need to get the
/// provider widget first and then we will return toolbar configurations
/// don't throw exception if [QuillBaseToolbarProvider] is not in the widget tree
QuillBaseToolbarConfigurations? get quillBaseToolbarConfigurations {
return QuillBaseToolbarProvider.of(this)?.toolbarConfigurations;
}
/// return nullable [QuillToolbarBaseButtonOptions]. Since the quill
/// toolbar base button options is in the [QuillProvider] then we need to
/// get the provider widget first and then we will return base button
/// don't throw exception if [QuillProvider] is not in the widget tree
QuillToolbarBaseButtonOptions? get quillToolbarBaseButtonOptions {
return quillToolbarConfigurations?.buttonOptions.base;
}
/// return [QuillToolbarBaseButtonOptions] as not null. Since the quill
/// toolbar base button options is in the [QuillProvider] then we need to
/// get the provider widget first and then we will return base button
/// throw exception if [QuillProvider] is not in the widget tree
QuillToolbarBaseButtonOptions get requireQuillToolbarBaseButtonOptions {
return quillToolbarConfigurations?.buttonOptions.base ??
quillBaseToolbarConfigurations?.buttonOptions.base ??
(throw ArgumentError(
"The buttonOptions is required and it's null because the toolbar configurations is.",
));
}
/// return nullable [QuillToolbarBaseButtonOptions]. Since the quill
/// quill editor block options is in the [QuillEditorProvider] then we need to
/// get the provider widget first and then we will return block options
/// throw exception if [QuillEditorProvider] is not in the widget tree
QuillEditorElementOptions? get quillEditorElementOptions {
return quillEditorConfigurations?.elementOptions;
}
/// return [QuillToolbarBaseButtonOptions] as not null. Since the quill
/// quill editor block options is in the [QuillEditorProvider] then we need to
/// get the provider widget first and then we will return block options
/// don't throw exception if [QuillEditorProvider] is not in the widget tree
QuillEditorElementOptions get requireQuillEditorElementOptions {
return requireQuillEditorConfigurations.elementOptions;
}
}

@ -0,0 +1,11 @@
extension UriExt on Uri {
bool isHttpBasedUrl() {
final uri = this;
return uri.isScheme('HTTP') || uri.isScheme('HTTPS');
}
bool isHttpsBasedUrl() {
final uri = this;
return uri.isScheme('HTTPS');
}
}

@ -421,6 +421,30 @@ abstract class FlutterQuillLocalizations {
/// **'Header style'**
String get headerStyle;
/// No description provided for @normal.
///
/// In en, this message translates to:
/// **'Normal'**
String get normal;
/// No description provided for @heading1.
///
/// In en, this message translates to:
/// **'Heading 1'**
String get heading1;
/// No description provided for @heading2.
///
/// In en, this message translates to:
/// **'Heading 2'**
String get heading2;
/// No description provided for @heading3.
///
/// In en, this message translates to:
/// **'Heading 3'**
String get heading3;
/// No description provided for @numberedList.
///
/// In en, this message translates to:
@ -610,7 +634,7 @@ abstract class FlutterQuillLocalizations {
/// No description provided for @takeAPhotoUsingYourCamera.
///
/// In en, this message translates to:
/// **'Take a photo using your phone camera'**
/// **'Take a photo using your camera'**
String get takeAPhotoUsingYourCamera;
/// No description provided for @pasteAPhotoUsingALink.
@ -628,7 +652,7 @@ abstract class FlutterQuillLocalizations {
/// No description provided for @recordAVideoUsingYourCamera.
///
/// In en, this message translates to:
/// **'Record a video using your phone camera'**
/// **'Record a video using your camera'**
String get recordAVideoUsingYourCamera;
/// No description provided for @pasteAVideoUsingALink.

@ -136,6 +136,18 @@ class FlutterQuillLocalizationsAr extends FlutterQuillLocalizations {
@override
String get headerStyle => 'ستايل العنوان';
@override
String get normal => 'Normal';
@override
String get heading1 => 'Heading 1';
@override
String get heading2 => 'Heading 2';
@override
String get heading3 => 'Heading 3';
@override
String get numberedList => 'قائمة مرقمة';
@ -231,8 +243,7 @@ class FlutterQuillLocalizationsAr extends FlutterQuillLocalizations {
String get pickAPhotoFromYourGallery => 'Pick a photo from your gallery';
@override
String get takeAPhotoUsingYourCamera =>
'Take a photo using your phone camera';
String get takeAPhotoUsingYourCamera => 'Take a photo using your camera';
@override
String get pasteAPhotoUsingALink => 'Paste a photo using a link';
@ -241,8 +252,7 @@ class FlutterQuillLocalizationsAr extends FlutterQuillLocalizations {
String get pickAVideoFromYourGallery => 'Pick a video from your gallery';
@override
String get recordAVideoUsingYourCamera =>
'Record a video using your phone camera';
String get recordAVideoUsingYourCamera => 'Record a video using your camera';
@override
String get pasteAVideoUsingALink => 'Paste a video using a link';

@ -136,6 +136,18 @@ class FlutterQuillLocalizationsBg extends FlutterQuillLocalizations {
@override
String get headerStyle => 'Стил на заглавието';
@override
String get normal => 'Normal';
@override
String get heading1 => 'Heading 1';
@override
String get heading2 => 'Heading 2';
@override
String get heading3 => 'Heading 3';
@override
String get numberedList => 'Номериран списък';
@ -233,8 +245,7 @@ class FlutterQuillLocalizationsBg extends FlutterQuillLocalizations {
String get pickAPhotoFromYourGallery => 'Pick a photo from your gallery';
@override
String get takeAPhotoUsingYourCamera =>
'Take a photo using your phone camera';
String get takeAPhotoUsingYourCamera => 'Take a photo using your camera';
@override
String get pasteAPhotoUsingALink => 'Paste a photo using a link';
@ -243,8 +254,7 @@ class FlutterQuillLocalizationsBg extends FlutterQuillLocalizations {
String get pickAVideoFromYourGallery => 'Pick a video from your gallery';
@override
String get recordAVideoUsingYourCamera =>
'Record a video using your phone camera';
String get recordAVideoUsingYourCamera => 'Record a video using your camera';
@override
String get pasteAVideoUsingALink => 'Paste a video using a link';

@ -136,6 +136,18 @@ class FlutterQuillLocalizationsBn extends FlutterQuillLocalizations {
@override
String get headerStyle => 'র সইল';
@override
String get normal => 'Normal';
@override
String get heading1 => 'Heading 1';
@override
String get heading2 => 'Heading 2';
@override
String get heading3 => 'Heading 3';
@override
String get numberedList => 'ত তি';
@ -233,8 +245,7 @@ class FlutterQuillLocalizationsBn extends FlutterQuillLocalizations {
String get pickAPhotoFromYourGallery => 'Pick a photo from your gallery';
@override
String get takeAPhotoUsingYourCamera =>
'Take a photo using your phone camera';
String get takeAPhotoUsingYourCamera => 'Take a photo using your camera';
@override
String get pasteAPhotoUsingALink => 'Paste a photo using a link';
@ -243,8 +254,7 @@ class FlutterQuillLocalizationsBn extends FlutterQuillLocalizations {
String get pickAVideoFromYourGallery => 'Pick a video from your gallery';
@override
String get recordAVideoUsingYourCamera =>
'Record a video using your phone camera';
String get recordAVideoUsingYourCamera => 'Record a video using your camera';
@override
String get pasteAVideoUsingALink => 'Paste a video using a link';

@ -136,6 +136,18 @@ class FlutterQuillLocalizationsCs extends FlutterQuillLocalizations {
@override
String get headerStyle => 'Styl záhlaví';
@override
String get normal => 'Normal';
@override
String get heading1 => 'Heading 1';
@override
String get heading2 => 'Heading 2';
@override
String get heading3 => 'Heading 3';
@override
String get numberedList => 'Číslovaný seznam';
@ -233,8 +245,7 @@ class FlutterQuillLocalizationsCs extends FlutterQuillLocalizations {
String get pickAPhotoFromYourGallery => 'Pick a photo from your gallery';
@override
String get takeAPhotoUsingYourCamera =>
'Take a photo using your phone camera';
String get takeAPhotoUsingYourCamera => 'Take a photo using your camera';
@override
String get pasteAPhotoUsingALink => 'Paste a photo using a link';
@ -243,8 +254,7 @@ class FlutterQuillLocalizationsCs extends FlutterQuillLocalizations {
String get pickAVideoFromYourGallery => 'Pick a video from your gallery';
@override
String get recordAVideoUsingYourCamera =>
'Record a video using your phone camera';
String get recordAVideoUsingYourCamera => 'Record a video using your camera';
@override
String get pasteAVideoUsingALink => 'Paste a video using a link';

@ -136,6 +136,18 @@ class FlutterQuillLocalizationsDa extends FlutterQuillLocalizations {
@override
String get headerStyle => 'Header style';
@override
String get normal => 'Normal';
@override
String get heading1 => 'Heading 1';
@override
String get heading2 => 'Heading 2';
@override
String get heading3 => 'Heading 3';
@override
String get numberedList => 'Numbered list';
@ -231,8 +243,7 @@ class FlutterQuillLocalizationsDa extends FlutterQuillLocalizations {
String get pickAPhotoFromYourGallery => 'Pick a photo from your gallery';
@override
String get takeAPhotoUsingYourCamera =>
'Take a photo using your phone camera';
String get takeAPhotoUsingYourCamera => 'Take a photo using your camera';
@override
String get pasteAPhotoUsingALink => 'Paste a photo using a link';
@ -241,8 +252,7 @@ class FlutterQuillLocalizationsDa extends FlutterQuillLocalizations {
String get pickAVideoFromYourGallery => 'Pick a video from your gallery';
@override
String get recordAVideoUsingYourCamera =>
'Record a video using your phone camera';
String get recordAVideoUsingYourCamera => 'Record a video using your camera';
@override
String get pasteAVideoUsingALink => 'Paste a video using a link';

@ -136,6 +136,18 @@ class FlutterQuillLocalizationsDe extends FlutterQuillLocalizations {
@override
String get headerStyle => 'Überschrift-Stil';
@override
String get normal => 'Normal';
@override
String get heading1 => 'Heading 1';
@override
String get heading2 => 'Heading 2';
@override
String get heading3 => 'Heading 3';
@override
String get numberedList => 'Nummerierte Liste';
@ -232,8 +244,7 @@ class FlutterQuillLocalizationsDe extends FlutterQuillLocalizations {
String get pickAPhotoFromYourGallery => 'Pick a photo from your gallery';
@override
String get takeAPhotoUsingYourCamera =>
'Take a photo using your phone camera';
String get takeAPhotoUsingYourCamera => 'Take a photo using your camera';
@override
String get pasteAPhotoUsingALink => 'Paste a photo using a link';
@ -242,8 +253,7 @@ class FlutterQuillLocalizationsDe extends FlutterQuillLocalizations {
String get pickAVideoFromYourGallery => 'Pick a video from your gallery';
@override
String get recordAVideoUsingYourCamera =>
'Record a video using your phone camera';
String get recordAVideoUsingYourCamera => 'Record a video using your camera';
@override
String get pasteAVideoUsingALink => 'Paste a video using a link';

@ -136,6 +136,18 @@ class FlutterQuillLocalizationsEn extends FlutterQuillLocalizations {
@override
String get headerStyle => 'Header style';
@override
String get normal => 'Normal';
@override
String get heading1 => 'Heading 1';
@override
String get heading2 => 'Heading 2';
@override
String get heading3 => 'Heading 3';
@override
String get numberedList => 'Numbered list';
@ -233,8 +245,7 @@ class FlutterQuillLocalizationsEn extends FlutterQuillLocalizations {
String get pickAPhotoFromYourGallery => 'Pick a photo from your gallery';
@override
String get takeAPhotoUsingYourCamera =>
'Take a photo using your phone camera';
String get takeAPhotoUsingYourCamera => 'Take a photo using your camera';
@override
String get pasteAPhotoUsingALink => 'Paste a photo using a link';
@ -243,8 +254,7 @@ class FlutterQuillLocalizationsEn extends FlutterQuillLocalizations {
String get pickAVideoFromYourGallery => 'Pick a video from your gallery';
@override
String get recordAVideoUsingYourCamera =>
'Record a video using your phone camera';
String get recordAVideoUsingYourCamera => 'Record a video using your camera';
@override
String get pasteAVideoUsingALink => 'Paste a video using a link';

@ -136,6 +136,18 @@ class FlutterQuillLocalizationsEs extends FlutterQuillLocalizations {
@override
String get headerStyle => 'Header style';
@override
String get normal => 'Normal';
@override
String get heading1 => 'Heading 1';
@override
String get heading2 => 'Heading 2';
@override
String get heading3 => 'Heading 3';
@override
String get numberedList => 'Numbered list';
@ -232,8 +244,7 @@ class FlutterQuillLocalizationsEs extends FlutterQuillLocalizations {
String get pickAPhotoFromYourGallery => 'Pick a photo from your gallery';
@override
String get takeAPhotoUsingYourCamera =>
'Take a photo using your phone camera';
String get takeAPhotoUsingYourCamera => 'Take a photo using your camera';
@override
String get pasteAPhotoUsingALink => 'Paste a photo using a link';
@ -242,8 +253,7 @@ class FlutterQuillLocalizationsEs extends FlutterQuillLocalizations {
String get pickAVideoFromYourGallery => 'Pick a video from your gallery';
@override
String get recordAVideoUsingYourCamera =>
'Record a video using your phone camera';
String get recordAVideoUsingYourCamera => 'Record a video using your camera';
@override
String get pasteAVideoUsingALink => 'Paste a video using a link';

@ -136,6 +136,18 @@ class FlutterQuillLocalizationsFa extends FlutterQuillLocalizations {
@override
String get headerStyle => 'سبک هدر';
@override
String get normal => 'Normal';
@override
String get heading1 => 'Heading 1';
@override
String get heading2 => 'Heading 2';
@override
String get heading3 => 'Heading 3';
@override
String get numberedList => 'لیست شمارهدار';
@ -234,8 +246,7 @@ class FlutterQuillLocalizationsFa extends FlutterQuillLocalizations {
String get pickAPhotoFromYourGallery => 'Pick a photo from your gallery';
@override
String get takeAPhotoUsingYourCamera =>
'Take a photo using your phone camera';
String get takeAPhotoUsingYourCamera => 'Take a photo using your camera';
@override
String get pasteAPhotoUsingALink => 'Paste a photo using a link';
@ -244,8 +255,7 @@ class FlutterQuillLocalizationsFa extends FlutterQuillLocalizations {
String get pickAVideoFromYourGallery => 'Pick a video from your gallery';
@override
String get recordAVideoUsingYourCamera =>
'Record a video using your phone camera';
String get recordAVideoUsingYourCamera => 'Record a video using your camera';
@override
String get pasteAVideoUsingALink => 'Paste a video using a link';

@ -136,6 +136,18 @@ class FlutterQuillLocalizationsFr extends FlutterQuillLocalizations {
@override
String get headerStyle => "Style d'en-tête";
@override
String get normal => 'Normal';
@override
String get heading1 => 'Heading 1';
@override
String get heading2 => 'Heading 2';
@override
String get heading3 => 'Heading 3';
@override
String get numberedList => 'Liste numérotée';
@ -235,8 +247,7 @@ class FlutterQuillLocalizationsFr extends FlutterQuillLocalizations {
String get pickAPhotoFromYourGallery => 'Pick a photo from your gallery';
@override
String get takeAPhotoUsingYourCamera =>
'Take a photo using your phone camera';
String get takeAPhotoUsingYourCamera => 'Take a photo using your camera';
@override
String get pasteAPhotoUsingALink => 'Paste a photo using a link';
@ -245,8 +256,7 @@ class FlutterQuillLocalizationsFr extends FlutterQuillLocalizations {
String get pickAVideoFromYourGallery => 'Pick a video from your gallery';
@override
String get recordAVideoUsingYourCamera =>
'Record a video using your phone camera';
String get recordAVideoUsingYourCamera => 'Record a video using your camera';
@override
String get pasteAVideoUsingALink => 'Paste a video using a link';

@ -136,6 +136,18 @@ class FlutterQuillLocalizationsHe extends FlutterQuillLocalizations {
@override
String get headerStyle => 'סגנון הכותרת';
@override
String get normal => 'Normal';
@override
String get heading1 => 'Heading 1';
@override
String get heading2 => 'Heading 2';
@override
String get heading3 => 'Heading 3';
@override
String get numberedList => 'רשימה ממוספרת';
@ -233,8 +245,7 @@ class FlutterQuillLocalizationsHe extends FlutterQuillLocalizations {
String get pickAPhotoFromYourGallery => 'Pick a photo from your gallery';
@override
String get takeAPhotoUsingYourCamera =>
'Take a photo using your phone camera';
String get takeAPhotoUsingYourCamera => 'Take a photo using your camera';
@override
String get pasteAPhotoUsingALink => 'Paste a photo using a link';
@ -243,8 +254,7 @@ class FlutterQuillLocalizationsHe extends FlutterQuillLocalizations {
String get pickAVideoFromYourGallery => 'Pick a video from your gallery';
@override
String get recordAVideoUsingYourCamera =>
'Record a video using your phone camera';
String get recordAVideoUsingYourCamera => 'Record a video using your camera';
@override
String get pasteAVideoUsingALink => 'Paste a video using a link';

@ -136,6 +136,18 @@ class FlutterQuillLocalizationsHi extends FlutterQuillLocalizations {
@override
String get headerStyle => 'डर श';
@override
String get normal => 'Normal';
@override
String get heading1 => 'Heading 1';
@override
String get heading2 => 'Heading 2';
@override
String get heading3 => 'Heading 3';
@override
String get numberedList => 'बदध स';
@ -234,8 +246,7 @@ class FlutterQuillLocalizationsHi extends FlutterQuillLocalizations {
String get pickAPhotoFromYourGallery => 'Pick a photo from your gallery';
@override
String get takeAPhotoUsingYourCamera =>
'Take a photo using your phone camera';
String get takeAPhotoUsingYourCamera => 'Take a photo using your camera';
@override
String get pasteAPhotoUsingALink => 'Paste a photo using a link';
@ -244,8 +255,7 @@ class FlutterQuillLocalizationsHi extends FlutterQuillLocalizations {
String get pickAVideoFromYourGallery => 'Pick a video from your gallery';
@override
String get recordAVideoUsingYourCamera =>
'Record a video using your phone camera';
String get recordAVideoUsingYourCamera => 'Record a video using your camera';
@override
String get pasteAVideoUsingALink => 'Paste a video using a link';

@ -136,6 +136,18 @@ class FlutterQuillLocalizationsId extends FlutterQuillLocalizations {
@override
String get headerStyle => 'Gaya Header';
@override
String get normal => 'Normal';
@override
String get heading1 => 'Heading 1';
@override
String get heading2 => 'Heading 2';
@override
String get heading3 => 'Heading 3';
@override
String get numberedList => 'Daftar Bernomor';
@ -235,8 +247,7 @@ class FlutterQuillLocalizationsId extends FlutterQuillLocalizations {
String get pickAPhotoFromYourGallery => 'Pick a photo from your gallery';
@override
String get takeAPhotoUsingYourCamera =>
'Take a photo using your phone camera';
String get takeAPhotoUsingYourCamera => 'Take a photo using your camera';
@override
String get pasteAPhotoUsingALink => 'Paste a photo using a link';
@ -245,8 +256,7 @@ class FlutterQuillLocalizationsId extends FlutterQuillLocalizations {
String get pickAVideoFromYourGallery => 'Pick a video from your gallery';
@override
String get recordAVideoUsingYourCamera =>
'Record a video using your phone camera';
String get recordAVideoUsingYourCamera => 'Record a video using your camera';
@override
String get pasteAVideoUsingALink => 'Paste a video using a link';

@ -136,6 +136,18 @@ class FlutterQuillLocalizationsIt extends FlutterQuillLocalizations {
@override
String get headerStyle => 'Stile intestazione';
@override
String get normal => 'Normal';
@override
String get heading1 => 'Heading 1';
@override
String get heading2 => 'Heading 2';
@override
String get heading3 => 'Heading 3';
@override
String get numberedList => 'Elenco numerato';
@ -235,8 +247,7 @@ class FlutterQuillLocalizationsIt extends FlutterQuillLocalizations {
String get pickAPhotoFromYourGallery => 'Pick a photo from your gallery';
@override
String get takeAPhotoUsingYourCamera =>
'Take a photo using your phone camera';
String get takeAPhotoUsingYourCamera => 'Take a photo using your camera';
@override
String get pasteAPhotoUsingALink => 'Paste a photo using a link';
@ -245,8 +256,7 @@ class FlutterQuillLocalizationsIt extends FlutterQuillLocalizations {
String get pickAVideoFromYourGallery => 'Pick a video from your gallery';
@override
String get recordAVideoUsingYourCamera =>
'Record a video using your phone camera';
String get recordAVideoUsingYourCamera => 'Record a video using your camera';
@override
String get pasteAVideoUsingALink => 'Paste a video using a link';

@ -136,6 +136,18 @@ class FlutterQuillLocalizationsJa extends FlutterQuillLocalizations {
@override
String get headerStyle => 'タイトルスタイル';
@override
String get normal => 'Normal';
@override
String get heading1 => 'Heading 1';
@override
String get heading2 => 'Heading 2';
@override
String get heading3 => 'Heading 3';
@override
String get numberedList => '順序付きリスト';
@ -230,8 +242,7 @@ class FlutterQuillLocalizationsJa extends FlutterQuillLocalizations {
String get pickAPhotoFromYourGallery => 'Pick a photo from your gallery';
@override
String get takeAPhotoUsingYourCamera =>
'Take a photo using your phone camera';
String get takeAPhotoUsingYourCamera => 'Take a photo using your camera';
@override
String get pasteAPhotoUsingALink => 'Paste a photo using a link';
@ -240,8 +251,7 @@ class FlutterQuillLocalizationsJa extends FlutterQuillLocalizations {
String get pickAVideoFromYourGallery => 'Pick a video from your gallery';
@override
String get recordAVideoUsingYourCamera =>
'Record a video using your phone camera';
String get recordAVideoUsingYourCamera => 'Record a video using your camera';
@override
String get pasteAVideoUsingALink => 'Paste a video using a link';

@ -136,6 +136,18 @@ class FlutterQuillLocalizationsKo extends FlutterQuillLocalizations {
@override
String get headerStyle => 'Header style';
@override
String get normal => 'Normal';
@override
String get heading1 => 'Heading 1';
@override
String get heading2 => 'Heading 2';
@override
String get heading3 => 'Heading 3';
@override
String get numberedList => 'Numbered list';
@ -230,8 +242,7 @@ class FlutterQuillLocalizationsKo extends FlutterQuillLocalizations {
String get pickAPhotoFromYourGallery => 'Pick a photo from your gallery';
@override
String get takeAPhotoUsingYourCamera =>
'Take a photo using your phone camera';
String get takeAPhotoUsingYourCamera => 'Take a photo using your camera';
@override
String get pasteAPhotoUsingALink => 'Paste a photo using a link';
@ -240,8 +251,7 @@ class FlutterQuillLocalizationsKo extends FlutterQuillLocalizations {
String get pickAVideoFromYourGallery => 'Pick a video from your gallery';
@override
String get recordAVideoUsingYourCamera =>
'Record a video using your phone camera';
String get recordAVideoUsingYourCamera => 'Record a video using your camera';
@override
String get pasteAVideoUsingALink => 'Paste a video using a link';

@ -136,6 +136,18 @@ class FlutterQuillLocalizationsMs extends FlutterQuillLocalizations {
@override
String get headerStyle => 'Header style';
@override
String get normal => 'Normal';
@override
String get heading1 => 'Heading 1';
@override
String get heading2 => 'Heading 2';
@override
String get heading3 => 'Heading 3';
@override
String get numberedList => 'Numbered list';
@ -233,8 +245,7 @@ class FlutterQuillLocalizationsMs extends FlutterQuillLocalizations {
String get pickAPhotoFromYourGallery => 'Pick a photo from your gallery';
@override
String get takeAPhotoUsingYourCamera =>
'Take a photo using your phone camera';
String get takeAPhotoUsingYourCamera => 'Take a photo using your camera';
@override
String get pasteAPhotoUsingALink => 'Paste a photo using a link';
@ -243,8 +254,7 @@ class FlutterQuillLocalizationsMs extends FlutterQuillLocalizations {
String get pickAVideoFromYourGallery => 'Pick a video from your gallery';
@override
String get recordAVideoUsingYourCamera =>
'Record a video using your phone camera';
String get recordAVideoUsingYourCamera => 'Record a video using your camera';
@override
String get pasteAVideoUsingALink => 'Paste a video using a link';

@ -136,6 +136,18 @@ class FlutterQuillLocalizationsNl extends FlutterQuillLocalizations {
@override
String get headerStyle => 'Header style';
@override
String get normal => 'Normal';
@override
String get heading1 => 'Heading 1';
@override
String get heading2 => 'Heading 2';
@override
String get heading3 => 'Heading 3';
@override
String get numberedList => 'Numbered list';
@ -235,8 +247,7 @@ class FlutterQuillLocalizationsNl extends FlutterQuillLocalizations {
String get pickAPhotoFromYourGallery => 'Pick a photo from your gallery';
@override
String get takeAPhotoUsingYourCamera =>
'Take a photo using your phone camera';
String get takeAPhotoUsingYourCamera => 'Take a photo using your camera';
@override
String get pasteAPhotoUsingALink => 'Paste a photo using a link';
@ -245,8 +256,7 @@ class FlutterQuillLocalizationsNl extends FlutterQuillLocalizations {
String get pickAVideoFromYourGallery => 'Pick a video from your gallery';
@override
String get recordAVideoUsingYourCamera =>
'Record a video using your phone camera';
String get recordAVideoUsingYourCamera => 'Record a video using your camera';
@override
String get pasteAVideoUsingALink => 'Paste a video using a link';

@ -136,6 +136,18 @@ class FlutterQuillLocalizationsNo extends FlutterQuillLocalizations {
@override
String get headerStyle => 'Overskriftsstil';
@override
String get normal => 'Normal';
@override
String get heading1 => 'Heading 1';
@override
String get heading2 => 'Heading 2';
@override
String get heading3 => 'Heading 3';
@override
String get numberedList => 'Nummerert liste';
@ -235,8 +247,7 @@ class FlutterQuillLocalizationsNo extends FlutterQuillLocalizations {
String get pickAPhotoFromYourGallery => 'Pick a photo from your gallery';
@override
String get takeAPhotoUsingYourCamera =>
'Take a photo using your phone camera';
String get takeAPhotoUsingYourCamera => 'Take a photo using your camera';
@override
String get pasteAPhotoUsingALink => 'Paste a photo using a link';
@ -245,8 +256,7 @@ class FlutterQuillLocalizationsNo extends FlutterQuillLocalizations {
String get pickAVideoFromYourGallery => 'Pick a video from your gallery';
@override
String get recordAVideoUsingYourCamera =>
'Record a video using your phone camera';
String get recordAVideoUsingYourCamera => 'Record a video using your camera';
@override
String get pasteAVideoUsingALink => 'Paste a video using a link';

@ -136,6 +136,18 @@ class FlutterQuillLocalizationsPl extends FlutterQuillLocalizations {
@override
String get headerStyle => 'Header style';
@override
String get normal => 'Normal';
@override
String get heading1 => 'Heading 1';
@override
String get heading2 => 'Heading 2';
@override
String get heading3 => 'Heading 3';
@override
String get numberedList => 'Numbered list';
@ -232,8 +244,7 @@ class FlutterQuillLocalizationsPl extends FlutterQuillLocalizations {
String get pickAPhotoFromYourGallery => 'Pick a photo from your gallery';
@override
String get takeAPhotoUsingYourCamera =>
'Take a photo using your phone camera';
String get takeAPhotoUsingYourCamera => 'Take a photo using your camera';
@override
String get pasteAPhotoUsingALink => 'Paste a photo using a link';
@ -242,8 +253,7 @@ class FlutterQuillLocalizationsPl extends FlutterQuillLocalizations {
String get pickAVideoFromYourGallery => 'Pick a video from your gallery';
@override
String get recordAVideoUsingYourCamera =>
'Record a video using your phone camera';
String get recordAVideoUsingYourCamera => 'Record a video using your camera';
@override
String get pasteAVideoUsingALink => 'Paste a video using a link';

@ -136,6 +136,18 @@ class FlutterQuillLocalizationsPt extends FlutterQuillLocalizations {
@override
String get headerStyle => 'Header style';
@override
String get normal => 'Normal';
@override
String get heading1 => 'Heading 1';
@override
String get heading2 => 'Heading 2';
@override
String get heading3 => 'Heading 3';
@override
String get numberedList => 'Numbered list';
@ -233,8 +245,7 @@ class FlutterQuillLocalizationsPt extends FlutterQuillLocalizations {
String get pickAPhotoFromYourGallery => 'Pick a photo from your gallery';
@override
String get takeAPhotoUsingYourCamera =>
'Take a photo using your phone camera';
String get takeAPhotoUsingYourCamera => 'Take a photo using your camera';
@override
String get pasteAPhotoUsingALink => 'Paste a photo using a link';
@ -243,8 +254,7 @@ class FlutterQuillLocalizationsPt extends FlutterQuillLocalizations {
String get pickAVideoFromYourGallery => 'Pick a video from your gallery';
@override
String get recordAVideoUsingYourCamera =>
'Record a video using your phone camera';
String get recordAVideoUsingYourCamera => 'Record a video using your camera';
@override
String get pasteAVideoUsingALink => 'Paste a video using a link';

@ -136,6 +136,18 @@ class FlutterQuillLocalizationsRu extends FlutterQuillLocalizations {
@override
String get headerStyle => 'Header style';
@override
String get normal => 'Normal';
@override
String get heading1 => 'Heading 1';
@override
String get heading2 => 'Heading 2';
@override
String get heading3 => 'Heading 3';
@override
String get numberedList => 'Numbered list';
@ -232,8 +244,7 @@ class FlutterQuillLocalizationsRu extends FlutterQuillLocalizations {
String get pickAPhotoFromYourGallery => 'Pick a photo from your gallery';
@override
String get takeAPhotoUsingYourCamera =>
'Take a photo using your phone camera';
String get takeAPhotoUsingYourCamera => 'Take a photo using your camera';
@override
String get pasteAPhotoUsingALink => 'Paste a photo using a link';
@ -242,8 +253,7 @@ class FlutterQuillLocalizationsRu extends FlutterQuillLocalizations {
String get pickAVideoFromYourGallery => 'Pick a video from your gallery';
@override
String get recordAVideoUsingYourCamera =>
'Record a video using your phone camera';
String get recordAVideoUsingYourCamera => 'Record a video using your camera';
@override
String get pasteAVideoUsingALink => 'Paste a video using a link';

@ -136,6 +136,18 @@ class FlutterQuillLocalizationsSr extends FlutterQuillLocalizations {
@override
String get headerStyle => 'Stil zaglavlja';
@override
String get normal => 'Normal';
@override
String get heading1 => 'Heading 1';
@override
String get heading2 => 'Heading 2';
@override
String get heading3 => 'Heading 3';
@override
String get numberedList => 'Numerisana lista';
@ -234,8 +246,7 @@ class FlutterQuillLocalizationsSr extends FlutterQuillLocalizations {
String get pickAPhotoFromYourGallery => 'Pick a photo from your gallery';
@override
String get takeAPhotoUsingYourCamera =>
'Take a photo using your phone camera';
String get takeAPhotoUsingYourCamera => 'Take a photo using your camera';
@override
String get pasteAPhotoUsingALink => 'Paste a photo using a link';
@ -244,8 +255,7 @@ class FlutterQuillLocalizationsSr extends FlutterQuillLocalizations {
String get pickAVideoFromYourGallery => 'Pick a video from your gallery';
@override
String get recordAVideoUsingYourCamera =>
'Record a video using your phone camera';
String get recordAVideoUsingYourCamera => 'Record a video using your camera';
@override
String get pasteAVideoUsingALink => 'Paste a video using a link';

@ -136,6 +136,18 @@ class FlutterQuillLocalizationsSw extends FlutterQuillLocalizations {
@override
String get headerStyle => 'Mtindo wa Mada';
@override
String get normal => 'Normal';
@override
String get heading1 => 'Heading 1';
@override
String get heading2 => 'Heading 2';
@override
String get heading3 => 'Heading 3';
@override
String get numberedList => 'Orodha ya Nambari';
@ -232,8 +244,7 @@ class FlutterQuillLocalizationsSw extends FlutterQuillLocalizations {
String get pickAPhotoFromYourGallery => 'Pick a photo from your gallery';
@override
String get takeAPhotoUsingYourCamera =>
'Take a photo using your phone camera';
String get takeAPhotoUsingYourCamera => 'Take a photo using your camera';
@override
String get pasteAPhotoUsingALink => 'Paste a photo using a link';
@ -242,8 +253,7 @@ class FlutterQuillLocalizationsSw extends FlutterQuillLocalizations {
String get pickAVideoFromYourGallery => 'Pick a video from your gallery';
@override
String get recordAVideoUsingYourCamera =>
'Record a video using your phone camera';
String get recordAVideoUsingYourCamera => 'Record a video using your camera';
@override
String get pasteAVideoUsingALink => 'Paste a video using a link';

@ -136,6 +136,18 @@ class FlutterQuillLocalizationsTk extends FlutterQuillLocalizations {
@override
String get headerStyle => 'Sözbaşy stili';
@override
String get normal => 'Normal';
@override
String get heading1 => 'Heading 1';
@override
String get heading2 => 'Heading 2';
@override
String get heading3 => 'Heading 3';
@override
String get numberedList => 'Sanly sanaw';
@ -231,8 +243,7 @@ class FlutterQuillLocalizationsTk extends FlutterQuillLocalizations {
String get pickAPhotoFromYourGallery => 'Pick a photo from your gallery';
@override
String get takeAPhotoUsingYourCamera =>
'Take a photo using your phone camera';
String get takeAPhotoUsingYourCamera => 'Take a photo using your camera';
@override
String get pasteAPhotoUsingALink => 'Paste a photo using a link';
@ -241,8 +252,7 @@ class FlutterQuillLocalizationsTk extends FlutterQuillLocalizations {
String get pickAVideoFromYourGallery => 'Pick a video from your gallery';
@override
String get recordAVideoUsingYourCamera =>
'Record a video using your phone camera';
String get recordAVideoUsingYourCamera => 'Record a video using your camera';
@override
String get pasteAVideoUsingALink => 'Paste a video using a link';

@ -136,6 +136,18 @@ class FlutterQuillLocalizationsTr extends FlutterQuillLocalizations {
@override
String get headerStyle => 'Başlık Stili';
@override
String get normal => 'Normal';
@override
String get heading1 => 'Heading 1';
@override
String get heading2 => 'Heading 2';
@override
String get heading3 => 'Heading 3';
@override
String get numberedList => 'Numaralı Liste';
@ -232,8 +244,7 @@ class FlutterQuillLocalizationsTr extends FlutterQuillLocalizations {
String get pickAPhotoFromYourGallery => 'Pick a photo from your gallery';
@override
String get takeAPhotoUsingYourCamera =>
'Take a photo using your phone camera';
String get takeAPhotoUsingYourCamera => 'Take a photo using your camera';
@override
String get pasteAPhotoUsingALink => 'Paste a photo using a link';
@ -242,8 +253,7 @@ class FlutterQuillLocalizationsTr extends FlutterQuillLocalizations {
String get pickAVideoFromYourGallery => 'Pick a video from your gallery';
@override
String get recordAVideoUsingYourCamera =>
'Record a video using your phone camera';
String get recordAVideoUsingYourCamera => 'Record a video using your camera';
@override
String get pasteAVideoUsingALink => 'Paste a video using a link';

@ -136,6 +136,18 @@ class FlutterQuillLocalizationsUk extends FlutterQuillLocalizations {
@override
String get headerStyle => 'Стиль заголовка';
@override
String get normal => 'Normal';
@override
String get heading1 => 'Heading 1';
@override
String get heading2 => 'Heading 2';
@override
String get heading3 => 'Heading 3';
@override
String get numberedList => 'Нумерований список';
@ -234,8 +246,7 @@ class FlutterQuillLocalizationsUk extends FlutterQuillLocalizations {
String get pickAPhotoFromYourGallery => 'Pick a photo from your gallery';
@override
String get takeAPhotoUsingYourCamera =>
'Take a photo using your phone camera';
String get takeAPhotoUsingYourCamera => 'Take a photo using your camera';
@override
String get pasteAPhotoUsingALink => 'Paste a photo using a link';
@ -244,8 +255,7 @@ class FlutterQuillLocalizationsUk extends FlutterQuillLocalizations {
String get pickAVideoFromYourGallery => 'Pick a video from your gallery';
@override
String get recordAVideoUsingYourCamera =>
'Record a video using your phone camera';
String get recordAVideoUsingYourCamera => 'Record a video using your camera';
@override
String get pasteAVideoUsingALink => 'Paste a video using a link';

@ -136,6 +136,18 @@ class FlutterQuillLocalizationsUr extends FlutterQuillLocalizations {
@override
String get headerStyle => 'ہیڈر کا انداز';
@override
String get normal => 'Normal';
@override
String get heading1 => 'Heading 1';
@override
String get heading2 => 'Heading 2';
@override
String get heading3 => 'Heading 3';
@override
String get numberedList => 'مرقم فہرست';
@ -236,8 +248,7 @@ class FlutterQuillLocalizationsUr extends FlutterQuillLocalizations {
String get pickAPhotoFromYourGallery => 'Pick a photo from your gallery';
@override
String get takeAPhotoUsingYourCamera =>
'Take a photo using your phone camera';
String get takeAPhotoUsingYourCamera => 'Take a photo using your camera';
@override
String get pasteAPhotoUsingALink => 'Paste a photo using a link';
@ -246,8 +257,7 @@ class FlutterQuillLocalizationsUr extends FlutterQuillLocalizations {
String get pickAVideoFromYourGallery => 'Pick a video from your gallery';
@override
String get recordAVideoUsingYourCamera =>
'Record a video using your phone camera';
String get recordAVideoUsingYourCamera => 'Record a video using your camera';
@override
String get pasteAVideoUsingALink => 'Paste a video using a link';

@ -136,6 +136,18 @@ class FlutterQuillLocalizationsVi extends FlutterQuillLocalizations {
@override
String get headerStyle => 'Kiểu tiêu đề';
@override
String get normal => 'Normal';
@override
String get heading1 => 'Heading 1';
@override
String get heading2 => 'Heading 2';
@override
String get heading3 => 'Heading 3';
@override
String get numberedList => 'Danh sách có số';
@ -233,8 +245,7 @@ class FlutterQuillLocalizationsVi extends FlutterQuillLocalizations {
String get pickAPhotoFromYourGallery => 'Pick a photo from your gallery';
@override
String get takeAPhotoUsingYourCamera =>
'Take a photo using your phone camera';
String get takeAPhotoUsingYourCamera => 'Take a photo using your camera';
@override
String get pasteAPhotoUsingALink => 'Paste a photo using a link';
@ -243,8 +254,7 @@ class FlutterQuillLocalizationsVi extends FlutterQuillLocalizations {
String get pickAVideoFromYourGallery => 'Pick a video from your gallery';
@override
String get recordAVideoUsingYourCamera =>
'Record a video using your phone camera';
String get recordAVideoUsingYourCamera => 'Record a video using your camera';
@override
String get pasteAVideoUsingALink => 'Paste a video using a link';

@ -136,6 +136,18 @@ class FlutterQuillLocalizationsZh extends FlutterQuillLocalizations {
@override
String get headerStyle => '标题样式';
@override
String get normal => 'Normal';
@override
String get heading1 => 'Heading 1';
@override
String get heading2 => 'Heading 2';
@override
String get heading3 => 'Heading 3';
@override
String get numberedList => '编号列表';
@ -230,8 +242,7 @@ class FlutterQuillLocalizationsZh extends FlutterQuillLocalizations {
String get pickAPhotoFromYourGallery => 'Pick a photo from your gallery';
@override
String get takeAPhotoUsingYourCamera =>
'Take a photo using your phone camera';
String get takeAPhotoUsingYourCamera => 'Take a photo using your camera';
@override
String get pasteAPhotoUsingALink => 'Paste a photo using a link';
@ -240,8 +251,7 @@ class FlutterQuillLocalizationsZh extends FlutterQuillLocalizations {
String get pickAVideoFromYourGallery => 'Pick a video from your gallery';
@override
String get recordAVideoUsingYourCamera =>
'Record a video using your phone camera';
String get recordAVideoUsingYourCamera => 'Record a video using your camera';
@override
String get pasteAVideoUsingALink => 'Paste a video using a link';

@ -44,6 +44,10 @@
"justifyWinWidth": "Justify win width",
"textDirection": "Text direction",
"headerStyle": "Header style",
"normal": "Normal",
"heading1": "Heading 1",
"heading2": "Heading 2",
"heading3": "Heading 3",
"numberedList": "Numbered list",
"bulletList": "Bullet list",
"checkedList": "Checked list",
@ -75,9 +79,9 @@
"caseSensitivityAndWholeWordSearch": "Case sensitivity and whole word search",
"insertImage": "Insert image",
"pickAPhotoFromYourGallery": "Pick a photo from your gallery",
"takeAPhotoUsingYourCamera": "Take a photo using your phone camera",
"takeAPhotoUsingYourCamera": "Take a photo using your camera",
"pasteAPhotoUsingALink": "Paste a photo using a link",
"pickAVideoFromYourGallery": "Pick a video from your gallery",
"recordAVideoUsingYourCamera": "Record a video using your phone camera",
"recordAVideoUsingYourCamera": "Record a video using your camera",
"pasteAVideoUsingALink": "Paste a video using a link"
}

@ -1,5 +1,9 @@
{
"ar": [
"normal",
"heading1",
"heading2",
"heading3",
"pickAPhotoFromYourGallery",
"takeAPhotoUsingYourCamera",
"pasteAPhotoUsingALink",
@ -9,6 +13,10 @@
],
"bg": [
"normal",
"heading1",
"heading2",
"heading3",
"pickAPhotoFromYourGallery",
"takeAPhotoUsingYourCamera",
"pasteAPhotoUsingALink",
@ -18,6 +26,10 @@
],
"bn": [
"normal",
"heading1",
"heading2",
"heading3",
"pickAPhotoFromYourGallery",
"takeAPhotoUsingYourCamera",
"pasteAPhotoUsingALink",
@ -27,6 +39,10 @@
],
"cs": [
"normal",
"heading1",
"heading2",
"heading3",
"pickAPhotoFromYourGallery",
"takeAPhotoUsingYourCamera",
"pasteAPhotoUsingALink",
@ -36,6 +52,10 @@
],
"da": [
"normal",
"heading1",
"heading2",
"heading3",
"pickAPhotoFromYourGallery",
"takeAPhotoUsingYourCamera",
"pasteAPhotoUsingALink",
@ -45,6 +65,10 @@
],
"de": [
"normal",
"heading1",
"heading2",
"heading3",
"pickAPhotoFromYourGallery",
"takeAPhotoUsingYourCamera",
"pasteAPhotoUsingALink",
@ -54,6 +78,10 @@
],
"en_US": [
"normal",
"heading1",
"heading2",
"heading3",
"pickAPhotoFromYourGallery",
"takeAPhotoUsingYourCamera",
"pasteAPhotoUsingALink",
@ -63,6 +91,10 @@
],
"es": [
"normal",
"heading1",
"heading2",
"heading3",
"pickAPhotoFromYourGallery",
"takeAPhotoUsingYourCamera",
"pasteAPhotoUsingALink",
@ -72,6 +104,10 @@
],
"fa": [
"normal",
"heading1",
"heading2",
"heading3",
"pickAPhotoFromYourGallery",
"takeAPhotoUsingYourCamera",
"pasteAPhotoUsingALink",
@ -81,6 +117,10 @@
],
"fr": [
"normal",
"heading1",
"heading2",
"heading3",
"pickAPhotoFromYourGallery",
"takeAPhotoUsingYourCamera",
"pasteAPhotoUsingALink",
@ -90,6 +130,10 @@
],
"he": [
"normal",
"heading1",
"heading2",
"heading3",
"pickAPhotoFromYourGallery",
"takeAPhotoUsingYourCamera",
"pasteAPhotoUsingALink",
@ -99,6 +143,10 @@
],
"hi": [
"normal",
"heading1",
"heading2",
"heading3",
"pickAPhotoFromYourGallery",
"takeAPhotoUsingYourCamera",
"pasteAPhotoUsingALink",
@ -108,6 +156,10 @@
],
"id": [
"normal",
"heading1",
"heading2",
"heading3",
"pickAPhotoFromYourGallery",
"takeAPhotoUsingYourCamera",
"pasteAPhotoUsingALink",
@ -117,6 +169,10 @@
],
"it": [
"normal",
"heading1",
"heading2",
"heading3",
"pickAPhotoFromYourGallery",
"takeAPhotoUsingYourCamera",
"pasteAPhotoUsingALink",
@ -126,6 +182,10 @@
],
"ja": [
"normal",
"heading1",
"heading2",
"heading3",
"pickAPhotoFromYourGallery",
"takeAPhotoUsingYourCamera",
"pasteAPhotoUsingALink",
@ -135,6 +195,10 @@
],
"ko": [
"normal",
"heading1",
"heading2",
"heading3",
"pickAPhotoFromYourGallery",
"takeAPhotoUsingYourCamera",
"pasteAPhotoUsingALink",
@ -144,6 +208,10 @@
],
"ms": [
"normal",
"heading1",
"heading2",
"heading3",
"pickAPhotoFromYourGallery",
"takeAPhotoUsingYourCamera",
"pasteAPhotoUsingALink",
@ -153,6 +221,10 @@
],
"nl": [
"normal",
"heading1",
"heading2",
"heading3",
"pickAPhotoFromYourGallery",
"takeAPhotoUsingYourCamera",
"pasteAPhotoUsingALink",
@ -162,6 +234,10 @@
],
"no": [
"normal",
"heading1",
"heading2",
"heading3",
"pickAPhotoFromYourGallery",
"takeAPhotoUsingYourCamera",
"pasteAPhotoUsingALink",
@ -171,6 +247,10 @@
],
"pl": [
"normal",
"heading1",
"heading2",
"heading3",
"pickAPhotoFromYourGallery",
"takeAPhotoUsingYourCamera",
"pasteAPhotoUsingALink",
@ -180,6 +260,10 @@
],
"pt": [
"normal",
"heading1",
"heading2",
"heading3",
"pickAPhotoFromYourGallery",
"takeAPhotoUsingYourCamera",
"pasteAPhotoUsingALink",
@ -189,6 +273,10 @@
],
"pt_BR": [
"normal",
"heading1",
"heading2",
"heading3",
"pickAPhotoFromYourGallery",
"takeAPhotoUsingYourCamera",
"pasteAPhotoUsingALink",
@ -198,6 +286,10 @@
],
"ru": [
"normal",
"heading1",
"heading2",
"heading3",
"pickAPhotoFromYourGallery",
"takeAPhotoUsingYourCamera",
"pasteAPhotoUsingALink",
@ -207,6 +299,10 @@
],
"sr": [
"normal",
"heading1",
"heading2",
"heading3",
"pickAPhotoFromYourGallery",
"takeAPhotoUsingYourCamera",
"pasteAPhotoUsingALink",
@ -216,6 +312,10 @@
],
"sw": [
"normal",
"heading1",
"heading2",
"heading3",
"pickAPhotoFromYourGallery",
"takeAPhotoUsingYourCamera",
"pasteAPhotoUsingALink",
@ -225,6 +325,10 @@
],
"tk": [
"normal",
"heading1",
"heading2",
"heading3",
"pickAPhotoFromYourGallery",
"takeAPhotoUsingYourCamera",
"pasteAPhotoUsingALink",
@ -234,6 +338,10 @@
],
"tr": [
"normal",
"heading1",
"heading2",
"heading3",
"pickAPhotoFromYourGallery",
"takeAPhotoUsingYourCamera",
"pasteAPhotoUsingALink",
@ -243,6 +351,10 @@
],
"uk": [
"normal",
"heading1",
"heading2",
"heading3",
"pickAPhotoFromYourGallery",
"takeAPhotoUsingYourCamera",
"pasteAPhotoUsingALink",
@ -252,6 +364,10 @@
],
"ur": [
"normal",
"heading1",
"heading2",
"heading3",
"pickAPhotoFromYourGallery",
"takeAPhotoUsingYourCamera",
"pasteAPhotoUsingALink",
@ -261,6 +377,10 @@
],
"vi": [
"normal",
"heading1",
"heading2",
"heading3",
"pickAPhotoFromYourGallery",
"takeAPhotoUsingYourCamera",
"pasteAPhotoUsingALink",
@ -270,6 +390,10 @@
],
"zh": [
"normal",
"heading1",
"heading2",
"heading3",
"pickAPhotoFromYourGallery",
"takeAPhotoUsingYourCamera",
"pasteAPhotoUsingALink",
@ -279,6 +403,10 @@
],
"zh_CN": [
"normal",
"heading1",
"heading2",
"heading3",
"pickAPhotoFromYourGallery",
"takeAPhotoUsingYourCamera",
"pasteAPhotoUsingALink",
@ -288,6 +416,10 @@
],
"zh_HK": [
"normal",
"heading1",
"heading2",
"heading3",
"pickAPhotoFromYourGallery",
"takeAPhotoUsingYourCamera",
"pasteAPhotoUsingALink",

@ -1,7 +1,7 @@
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import '../../extensions/quill_provider.dart';
import '../../extensions/quill_configurations_ext.dart';
import '../extensions/localizations.dart';
class FlutterQuillLocalizationsWidget extends StatelessWidget {
@ -19,7 +19,7 @@ class FlutterQuillLocalizationsWidget extends StatelessWidget {
return child;
}
return Localizations(
locale: context.requireQuillSharedConfigurations.locale ??
locale: context.quillSharedConfigurations?.locale ??
Localizations.localeOf(context),
delegates: FlutterQuillLocalizations.localizationsDelegates,
child: child,

@ -6,14 +6,15 @@ import 'package:flutter/material.dart'
import 'package:flutter/widgets.dart';
import 'package:meta/meta.dart' show experimental;
import '../../../widgets/default_styles.dart';
import '../../../widgets/delegate.dart';
import '../../../widgets/editor/editor.dart';
import '../../../widgets/editor/editor_builder.dart';
import '../../../widgets/embeds.dart';
import '../../../widgets/link.dart';
import '../../../widgets/others/default_styles.dart';
import '../../../widgets/others/delegate.dart';
import '../../../widgets/others/link.dart';
import '../../../widgets/quill/embeds.dart';
import '../../../widgets/quill/quill_controller.dart';
import '../../../widgets/raw_editor/raw_editor.dart';
import '../../themes/quill_dialog_theme.dart';
import '../quill_shared_configurations.dart';
import 'element_options.dart';
export 'element_options.dart';
@ -24,6 +25,8 @@ class QuillEditorConfigurations extends Equatable {
/// Important note for the maintainers
/// When editing this class please update the [copyWith] function too.
const QuillEditorConfigurations({
required this.controller,
this.sharedConfigurations = const QuillSharedConfigurations(),
this.scrollable = true,
this.padding = EdgeInsets.zero,
this.autoFocus = false,
@ -74,6 +77,10 @@ class QuillEditorConfigurations extends Equatable {
this.textInputAction = TextInputAction.newline,
});
final QuillSharedConfigurations sharedConfigurations;
final QuillController controller;
/// The text placeholder in the quill editor
final String? placeholder;
@ -331,6 +338,8 @@ class QuillEditorConfigurations extends Equatable {
// regenerate this function using extension in vs code or plugin in intellij
QuillEditorConfigurations copyWith({
QuillSharedConfigurations? sharedConfigurations,
QuillController? controller,
String? placeholder,
bool? readOnly,
bool? scrollable,
@ -376,6 +385,8 @@ class QuillEditorConfigurations extends Equatable {
TextInputAction? textInputAction,
}) {
return QuillEditorConfigurations(
sharedConfigurations: sharedConfigurations ?? this.sharedConfigurations,
controller: controller ?? this.controller,
placeholder: placeholder ?? this.placeholder,
readOnly: readOnly ?? this.readOnly,
scrollable: scrollable ?? this.scrollable,

@ -2,16 +2,25 @@ import 'package:equatable/equatable.dart';
import 'package:flutter/foundation.dart' show immutable;
import 'elements/code_block.dart';
import 'elements/list/ordered_list.dart';
import 'elements/list/unordered_list.dart';
export 'elements/code_block.dart';
export 'elements/list/ordered_list.dart';
export 'elements/list/unordered_list.dart';
@immutable
class QuillEditorElementOptions extends Equatable {
const QuillEditorElementOptions({
this.codeBlock = const QuillEditorCodeBlockElementOptions(),
this.orderedList = const QuillEditorOrderedListElementOptions(),
this.unorderedList = const QuillEditorUnOrderedListElementOptions(),
});
final QuillEditorCodeBlockElementOptions codeBlock;
final QuillEditorOrderedListElementOptions orderedList;
final QuillEditorUnOrderedListElementOptions unorderedList;
@override
List<Object?> get props => [
codeBlock,

@ -0,0 +1,14 @@
import 'package:equatable/equatable.dart';
import 'package:flutter/foundation.dart' show immutable;
import 'package:flutter/widgets.dart' show Color;
@immutable
class QuillEditorOrderedListElementOptions extends Equatable {
const QuillEditorOrderedListElementOptions(
{this.backgroundColor, this.fontColor});
final Color? backgroundColor;
final Color? fontColor;
@override
List<Object?> get props => [];
}

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save