diff --git a/doc/migration.md b/doc/migration.md index 8c3a175c..e7b3908f 100644 --- a/doc/migration.md +++ b/doc/migration.md @@ -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 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 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 { - 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 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 \ No newline at end of file diff --git a/doc/migration/7_8.md b/doc/migration/7_8.md new file mode 100644 index 00000000..e797ca30 --- /dev/null +++ b/doc/migration/7_8.md @@ -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 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 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 { + 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 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 diff --git a/doc/migration/8_9.md b/doc/migration/8_9.md new file mode 100644 index 00000000..ade5124b --- /dev/null +++ b/doc/migration/8_9.md @@ -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 \ No newline at end of file diff --git a/example/lib/presentation/simple/simple_screen.dart b/example/lib/presentation/simple/simple_screen.dart index 0393fcf7..2fc3a138 100644 --- a/example/lib/presentation/simple/simple_screen.dart +++ b/example/lib/presentation/simple/simple_screen.dart @@ -13,6 +13,17 @@ class _SimpleScreenState extends State { @override Widget build(BuildContext context) { + return Column( + children: [ + QuillToolbar.simple( + QuillSimpleToolbarConfigurations(controller: _controller)), + Expanded( + child: QuillEditor.basic( + configurations: QuillEditorConfigurations(controller: _controller), + ), + ) + ], + ); return Scaffold( appBar: AppBar(), body: Column( diff --git a/flutter_quill_extensions/lib/embeds/widgets/image.dart b/flutter_quill_extensions/lib/embeds/widgets/image.dart index d072f202..03168b60 100644 --- a/flutter_quill_extensions/lib/embeds/widgets/image.dart +++ b/flutter_quill_extensions/lib/embeds/widgets/image.dart @@ -50,7 +50,6 @@ ImageProvider getImageProviderByImageSource( } if (imageSource.startsWith(assetsPrefix)) { - // TODO: This impl could be improved return AssetImage(imageSource); } return FileImage(File(imageSource)); diff --git a/flutter_quill_extensions/lib/utils/element_utils/element_utils.dart b/flutter_quill_extensions/lib/utils/element_utils/element_utils.dart index 64db01ae..6be7c163 100644 --- a/flutter_quill_extensions/lib/utils/element_utils/element_utils.dart +++ b/flutter_quill_extensions/lib/utils/element_utils/element_utils.dart @@ -51,7 +51,6 @@ enum ExtraElementProperties { final cssAttrs = parseCssString(cssStyle.value.toString()); - // todo: This could be improved much better final cssHeightValue = parseCssPropertyAsDouble( (cssAttrs[Attribute.height.key]) ?? '', context: context, diff --git a/lib/flutter_quill.dart b/lib/flutter_quill.dart index 5ea179f4..54f4eaec 100644 --- a/lib/flutter_quill.dart +++ b/lib/flutter_quill.dart @@ -2,7 +2,7 @@ library flutter_quill; 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/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'; diff --git a/lib/src/extensions/quill_configurations_ext.dart b/lib/src/extensions/quill_configurations_ext.dart index f926f76e..a7da7df3 100644 --- a/lib/src/extensions/quill_configurations_ext.dart +++ b/lib/src/extensions/quill_configurations_ext.dart @@ -57,12 +57,12 @@ extension QuillEditorExt on BuildContext { extension QuillSimpleToolbarExt on BuildContext { /// return [QuillSimpleToolbarConfigurations] as not null QuillSimpleToolbarConfigurations get requireQuillSimpleToolbarConfigurations { - return QuillToolbarProvider.ofNotNull(this).toolbarConfigurations; + return QuillSimpleToolbarProvider.ofNotNull(this).toolbarConfigurations; } /// return nullable [QuillSimpleToolbarConfigurations] QuillSimpleToolbarConfigurations? get quillSimpleToolbarConfigurations { - return QuillToolbarProvider.of(this)?.toolbarConfigurations; + return QuillSimpleToolbarProvider.of(this)?.toolbarConfigurations; } /// return nullable [QuillToolbarBaseButtonOptions]. @@ -83,11 +83,11 @@ extension QuillSimpleToolbarExt on BuildContext { extension QuillToolbarExt on BuildContext { /// return [QuillToolbarConfigurations] as not null QuillToolbarConfigurations get requireQuillToolbarConfigurations { - return QuillBaseToolbarProvider.ofNotNull(this).toolbarConfigurations; + return QuillToolbarProvider.ofNotNull(this).toolbarConfigurations; } /// return nullable [QuillToolbarConfigurations]. QuillToolbarConfigurations? get quillToolbarConfigurations { - return QuillBaseToolbarProvider.of(this)?.toolbarConfigurations; + return QuillToolbarProvider.of(this)?.toolbarConfigurations; } } diff --git a/lib/src/extensions/uri_ext.dart b/lib/src/extensions/uri_ext.dart new file mode 100644 index 00000000..b548a29c --- /dev/null +++ b/lib/src/extensions/uri_ext.dart @@ -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'); + } +} diff --git a/lib/src/models/config/editor/configurations.dart b/lib/src/models/config/editor/editor_configurations.dart similarity index 100% rename from lib/src/models/config/editor/configurations.dart rename to lib/src/models/config/editor/editor_configurations.dart diff --git a/lib/src/models/config/quill_configurations.dart b/lib/src/models/config/quill_configurations.dart index 60b30aaf..b673ba39 100644 --- a/lib/src/models/config/quill_configurations.dart +++ b/lib/src/models/config/quill_configurations.dart @@ -3,7 +3,7 @@ import 'package:flutter/foundation.dart' show immutable; import '../../../flutter_quill.dart'; -export './editor/configurations.dart'; +export 'editor/editor_configurations.dart'; export 'quill_shared_configurations.dart'; export 'toolbar/simple_toolbar_configurations.dart'; diff --git a/lib/src/models/config/quill_shared_configurations.dart b/lib/src/models/config/quill_shared_configurations.dart index ddf5f776..beadc432 100644 --- a/lib/src/models/config/quill_shared_configurations.dart +++ b/lib/src/models/config/quill_shared_configurations.dart @@ -2,7 +2,7 @@ import 'package:equatable/equatable.dart'; import 'package:flutter/material.dart' show Color, Colors, Locale; import '../themes/quill_dialog_theme.dart'; -import './editor/configurations.dart' show QuillEditorConfigurations; +import 'editor/editor_configurations.dart' show QuillEditorConfigurations; import 'toolbar/simple_toolbar_configurations.dart' show QuillSimpleToolbarConfigurations; diff --git a/lib/src/models/config/raw_editor/configurations.dart b/lib/src/models/config/raw_editor/raw_editor_configurations.dart similarity index 100% rename from lib/src/models/config/raw_editor/configurations.dart rename to lib/src/models/config/raw_editor/raw_editor_configurations.dart diff --git a/lib/src/models/rules/insert.dart b/lib/src/models/rules/insert.dart index daf3c110..f57cb910 100644 --- a/lib/src/models/rules/insert.dart +++ b/lib/src/models/rules/insert.dart @@ -1,5 +1,6 @@ import 'package:meta/meta.dart' show immutable; +import '../../extensions/uri_ext.dart'; import '../../models/documents/document.dart'; import '../documents/attribute.dart'; import '../documents/nodes/embeddable.dart'; @@ -520,8 +521,7 @@ class AutoFormatLinksRule extends InsertRule { try { final cand = (prev.data as String).split('\n').last.split(' ').last; final link = Uri.parse(cand); - // TODO: Can be improved a little - if (!['https', 'http'].contains(link.scheme)) { + if (!link.isHttpBasedUrl()) { return null; } final attributes = prev.attributes ?? {}; diff --git a/lib/src/widgets/editor/editor.dart b/lib/src/widgets/editor/editor.dart index 3964cd64..68665809 100644 --- a/lib/src/widgets/editor/editor.dart +++ b/lib/src/widgets/editor/editor.dart @@ -9,8 +9,8 @@ import 'package:flutter/rendering.dart'; import 'package:flutter/services.dart'; import '../../l10n/widgets/localizations.dart'; -import '../../models/config/editor/configurations.dart'; -import '../../models/config/raw_editor/configurations.dart'; +import '../../models/config/editor/editor_configurations.dart'; +import '../../models/config/raw_editor/raw_editor_configurations.dart'; import '../../models/documents/document.dart'; import '../../models/documents/nodes/container.dart' as container_node; import '../../models/documents/nodes/leaf.dart'; @@ -1209,28 +1209,6 @@ class RenderEditor extends RenderEditableContainerBox @override Rect getLocalRectForCaret(TextPosition position) { final targetChild = childAtPosition(position); - // TODO: There is a bug here - // The provided text position is not in the current node - // 'package:flutter_quill/src/widgets/text_block.dart': - // text_block.dart:1 - // Failed assertion: line 604 pos 12: - // 'container.containsOffset(position.offset)' - // When the exception was thrown, this was the stack - // #2 RenderEditableTextBlock.globalToLocalPosition - // text_block.dart:604 - // #3 RenderEditor.getLocalRectForCaret - // editor.dart:1230 - // #4 RawEditorStateTextInputClientMixin._updateComposingRectIfNeeded - // raw_editor_state_text_input_client_mixin.dart:85 - // #5 RawEditorStateTextInputClientMixin.openConnectionIfNeeded - // raw_editor_state_text_input_client_mixin.dart:70 - // #6 RawEditorState.requestKeyboard - // raw_editor.dart:1428 - // #7 QuillEditorState._requestKeyboard - // editor.dart:379 - // #8 _QuillEditorSelectionGestureDetectorBuilder.onSingleTapUp - // editor.dart:538 - // #9 _EditorTextSelectionGestureDetectorState._handleTapUp final localPosition = targetChild.globalToLocalPosition(position); final childLocalRect = targetChild.getLocalRectForCaret(localPosition); diff --git a/lib/src/widgets/others/delegate.dart b/lib/src/widgets/others/delegate.dart index b34874d0..3bf19cdc 100644 --- a/lib/src/widgets/others/delegate.dart +++ b/lib/src/widgets/others/delegate.dart @@ -332,8 +332,6 @@ class EditorTextSelectionGestureDetectorBuilder { @protected void onDragSelectionEnd(DragEndDetails details) { renderEditor!.handleDragEnd(details); - // TODO: Should we care if the platform is desktop using native desktop app - // or the flutter app is running using web app?? if (isDesktop(supportWeb: true) && delegate.selectionEnabled && shouldShowSelectionToolbar) { diff --git a/lib/src/widgets/others/proxy.dart b/lib/src/widgets/others/proxy.dart index 698497f4..6039a009 100644 --- a/lib/src/widgets/others/proxy.dart +++ b/lib/src/widgets/others/proxy.dart @@ -136,8 +136,7 @@ class RichTextProxy extends SingleChildRenderObjectWidget { required this.textDirection, required this.locale, required this.strutStyle, - // TODO: This might needs to be updated, previous value was 1.0 using `textScaleFactor` - this.textScaler = const TextScaler.linear(1), + required this.textScaler, this.textWidthBasis = TextWidthBasis.parent, this.textHeightBehavior, super.key, diff --git a/lib/src/widgets/others/text_line.dart b/lib/src/widgets/others/text_line.dart index 0067c958..3a155333 100644 --- a/lib/src/widgets/others/text_line.dart +++ b/lib/src/widgets/others/text_line.dart @@ -175,11 +175,12 @@ class _TextLineState extends State { textScaler: MediaQuery.textScalerOf(context), ); return RichTextProxy( - textStyle: textSpan.style!, + textStyle: textSpan.style ?? const TextStyle(), textAlign: textAlign, textDirection: widget.textDirection!, strutStyle: strutStyle, locale: Localizations.localeOf(context), + textScaler: MediaQuery.textScalerOf(context), child: child, ); } diff --git a/lib/src/widgets/raw_editor/raw_editor.dart b/lib/src/widgets/raw_editor/raw_editor.dart index 4e11d707..b69b7515 100644 --- a/lib/src/widgets/raw_editor/raw_editor.dart +++ b/lib/src/widgets/raw_editor/raw_editor.dart @@ -9,7 +9,7 @@ import 'package:flutter/widgets.dart' Widget; import 'package:meta/meta.dart' show immutable; -import '../../models/config/raw_editor/configurations.dart'; +import '../../models/config/raw_editor/raw_editor_configurations.dart'; import '../../models/structs/offset_value.dart'; import '../editor/editor.dart'; import '../others/text_selection.dart'; diff --git a/lib/src/widgets/toolbar/base_toolbar.dart b/lib/src/widgets/toolbar/base_toolbar.dart index 33e0f127..5b798219 100644 --- a/lib/src/widgets/toolbar/base_toolbar.dart +++ b/lib/src/widgets/toolbar/base_toolbar.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; import '../../../flutter_quill.dart' - show QuillBaseToolbarProvider, defaultToolbarSize; + show QuillToolbarProvider, defaultToolbarSize; import '../../l10n/widgets/localizations.dart'; import '../../models/config/toolbar/simple_toolbar_configurations.dart'; import '../../models/config/toolbar/toolbar_configurations.dart'; @@ -55,7 +55,7 @@ class QuillToolbar extends StatelessWidget implements PreferredSizeWidget { @override Widget build(BuildContext context) { return FlutterQuillLocalizationsWidget( - child: QuillBaseToolbarProvider( + child: QuillToolbarProvider( toolbarConfigurations: configurations, child: configurations.child, ), diff --git a/lib/src/widgets/toolbar/buttons/link_style_button.dart b/lib/src/widgets/toolbar/buttons/link_style_button.dart index 82ad9345..e52533d1 100644 --- a/lib/src/widgets/toolbar/buttons/link_style_button.dart +++ b/lib/src/widgets/toolbar/buttons/link_style_button.dart @@ -155,7 +155,7 @@ class QuillToolbarLinkStyleButtonState } Future _openLinkDialog(BuildContext context) async { - // TODO: Add a custom call back to customize this just like in the search + // TODO: Add a custom call back to customize this just like in the search dialog // button final value = await showDialog<_TextLink>( context: context, diff --git a/lib/src/widgets/toolbar/simple_toolbar.dart b/lib/src/widgets/toolbar/simple_toolbar.dart index 483667f2..0bec7cc1 100644 --- a/lib/src/widgets/toolbar/simple_toolbar.dart +++ b/lib/src/widgets/toolbar/simple_toolbar.dart @@ -423,7 +423,7 @@ class QuillSimpleToolbar extends StatelessWidget ]; } - return QuillToolbarProvider( + return QuillSimpleToolbarProvider( toolbarConfigurations: configurations, child: QuillToolbar( configurations: QuillToolbarConfigurations( diff --git a/lib/src/widgets/utils/provider.dart b/lib/src/widgets/utils/provider.dart index f7fbc02c..ab3e2903 100644 --- a/lib/src/widgets/utils/provider.dart +++ b/lib/src/widgets/utils/provider.dart @@ -5,8 +5,8 @@ import 'package:flutter/widgets.dart' import '../../models/config/quill_configurations.dart'; import '../../models/config/toolbar/toolbar_configurations.dart'; -class QuillToolbarProvider extends InheritedWidget { - const QuillToolbarProvider({ +class QuillSimpleToolbarProvider extends InheritedWidget { + const QuillSimpleToolbarProvider({ required super.child, required this.toolbarConfigurations, super.key, @@ -16,16 +16,17 @@ class QuillToolbarProvider extends InheritedWidget { final QuillSimpleToolbarConfigurations toolbarConfigurations; @override - bool updateShouldNotify(covariant QuillToolbarProvider oldWidget) { + bool updateShouldNotify(covariant QuillSimpleToolbarProvider oldWidget) { return oldWidget.toolbarConfigurations != toolbarConfigurations; } - static QuillToolbarProvider? of(BuildContext context) { + static QuillSimpleToolbarProvider? of(BuildContext context) { /// The configurations for the quill editor widget of flutter quill - return context.dependOnInheritedWidgetOfExactType(); + return context + .dependOnInheritedWidgetOfExactType(); } - static QuillToolbarProvider ofNotNull(BuildContext context) { + static QuillSimpleToolbarProvider ofNotNull(BuildContext context) { final provider = of(context); if (provider == null) { if (kDebugMode) { @@ -49,13 +50,13 @@ class QuillToolbarProvider extends InheritedWidget { return provider; } - /// To pass the [QuillToolbarProvider] instance as value instead of creating + /// To pass the [QuillSimpleToolbarProvider] instance as value instead of creating /// new widget - static QuillToolbarProvider value({ - required QuillToolbarProvider value, + static QuillSimpleToolbarProvider value({ + required QuillSimpleToolbarProvider value, required Widget child, }) { - return QuillToolbarProvider( + return QuillSimpleToolbarProvider( toolbarConfigurations: value.toolbarConfigurations, child: child, ); @@ -63,8 +64,8 @@ class QuillToolbarProvider extends InheritedWidget { } // Not really needed -class QuillBaseToolbarProvider extends InheritedWidget { - const QuillBaseToolbarProvider({ +class QuillToolbarProvider extends InheritedWidget { + const QuillToolbarProvider({ required super.child, required this.toolbarConfigurations, super.key, @@ -74,17 +75,16 @@ class QuillBaseToolbarProvider extends InheritedWidget { final QuillToolbarConfigurations toolbarConfigurations; @override - bool updateShouldNotify(covariant QuillBaseToolbarProvider oldWidget) { + bool updateShouldNotify(covariant QuillToolbarProvider oldWidget) { return oldWidget.toolbarConfigurations != toolbarConfigurations; } - static QuillBaseToolbarProvider? of(BuildContext context) { + static QuillToolbarProvider? of(BuildContext context) { /// The configurations for the quill editor widget of flutter quill - return context - .dependOnInheritedWidgetOfExactType(); + return context.dependOnInheritedWidgetOfExactType(); } - static QuillBaseToolbarProvider ofNotNull(BuildContext context) { + static QuillToolbarProvider ofNotNull(BuildContext context) { final provider = of(context); if (provider == null) { if (kDebugMode) { @@ -110,11 +110,11 @@ class QuillBaseToolbarProvider extends InheritedWidget { /// To pass the [QuillToolbarConfigurations] instance as value /// instead of creating new widget - static QuillBaseToolbarProvider value({ + static QuillToolbarProvider value({ required QuillToolbarConfigurations value, required Widget child, }) { - return QuillBaseToolbarProvider( + return QuillToolbarProvider( toolbarConfigurations: value, child: child, );