From 45214576f538fb9a9c04761e1dc069d8de6f5bb6 Mon Sep 17 00:00:00 2001
From: Ahmed Hnewa <73608287+freshtechtips@users.noreply.github.com>
Date: Sat, 21 Oct 2023 02:25:31 +0300
Subject: [PATCH] The first steps of the major update (#1444)
---
.github/PULL_REQUEST_TEMPLATE.md | 9 +-
CHANGELOG.md | 4 +
README.md | 24 +-
example/android/app/build.gradle | 3 +-
example/lib/main.dart | 13 -
example/lib/pages/home_page.dart | 301 ++++----
example/lib/pages/read_only_page.dart | 9 +-
example/lib/widgets/demo_scaffold.dart | 66 +-
example/macos/Podfile | 2 +-
.../macos/Runner.xcodeproj/project.pbxproj | 56 +-
.../xcshareddata/xcschemes/Runner.xcscheme | 178 ++---
example/pubspec.yaml | 68 +-
flutter_quill_extensions/pubspec.yaml | 9 +-
lib/flutter_quill.dart | 2 +
lib/src/core/quill_configurations.dart | 54 ++
lib/src/models/documents/nodes/container.dart | 3 +-
lib/src/models/documents/nodes/leaf.dart | 28 +-
lib/src/models/documents/nodes/line.dart | 8 +-
lib/src/test/widget_tester_extension.dart | 2 +-
lib/src/utils/extensions/build_context.dart | 37 +
lib/src/widgets/editor.dart | 28 +-
.../widgets/{ => raw_editor}/raw_editor.dart | 68 +-
lib/src/widgets/text_line.dart | 16 +-
lib/src/widgets/toolbar.dart | 719 +++++++++---------
.../widgets/toolbar/link_style_button2.dart | 3 +-
lib/src/widgets/utils/provider.dart | 50 ++
pubspec.yaml | 44 +-
test/bug_fix_test.dart | 63 +-
test/widgets/editor_test.dart | 67 +-
29 files changed, 1059 insertions(+), 875 deletions(-)
create mode 100644 lib/src/core/quill_configurations.dart
create mode 100644 lib/src/utils/extensions/build_context.dart
rename lib/src/widgets/{ => raw_editor}/raw_editor.dart (98%)
create mode 100644 lib/src/widgets/utils/provider.dart
diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
index 555a1e40..d365462e 100644
--- a/.github/PULL_REQUEST_TEMPLATE.md
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -11,18 +11,18 @@ Closes #IssueNumber
(Replace "IssueNumber" with the actual issue number you are addressing.)
## Improvements
-
+
- Improve code readability
-- Improve peformance
+- Improve performance
## Features
- Add a new feature
-- Allow to custmize the widgets
+- Allow to customize the widgets
@@ -40,5 +40,6 @@ Closes #IssueNumber
- [ ] I have tested these changes locally.
- [ ] I have followed the code style and guidelines.
- [ ] I have updated `CHANGELOG.md` with my changes in the next section
-- [ ] I have run "dart format ." on the project
+- [ ] I have run `dart format .`` on the project
+- [ ] I have run `dart fix --apply` on the project
- [ ] I have run `flutter test` and `flutter analyze` and it passed successfully
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 7200ae2e..eeffd94f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,7 @@
+# [7.5.0]
+
+- **Breaking change**: The widgets `QuillEditor` and `QuillToolbar` are no longer have controller parameter, instead you need to make sure in the widget tree you have wrapped them with `QuillProvider` widget and provide the controller and the require configurations
+
# [7.4.16]
- Update documentation and README.md
diff --git a/README.md b/README.md
index 2c3cfdff..5b9c4762 100644
--- a/README.md
+++ b/README.md
@@ -53,21 +53,25 @@ QuillController _controller = QuillController.basic();
and then embed the toolbar and the editor, within your app. For example:
```dart
-Column(
+QuillProvider(
+ configurations: QuillConfigurations(controller: _controller),
+ child: Column(
children: [
QuillToolbar.basic(controller: _controller),
Expanded(
child: Container(
child: QuillEditor.basic(
- controller: _controller,
readOnly: false, // true for view only mode
),
),
)
],
+),
)
```
+And depending on your use case, you might want to dispose the `_controller` in dispose mehtod
+
Check out [Sample Page] for advanced usage.
## Input / Output
@@ -476,6 +480,22 @@ and then enter text using `quillEnterText`:
await tester.quillEnterText(find.byType(QuillEditor), 'test\n');
```
+## License
+
+[MIT](LICENSE)
+
+## Contributors
+
+Special thanks for everyone that have contributed to this project...
+
+
+
+
+
+
+
+Made with [contrib.rocks](https://contrib.rocks).
+
## Sponsors
diff --git a/example/android/app/build.gradle b/example/android/app/build.gradle
index 9e1d2fc5..4eef2899 100644
--- a/example/android/app/build.gradle
+++ b/example/android/app/build.gradle
@@ -47,7 +47,7 @@ android {
targetSdkVersion flutter.targetSdkVersion
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
- multiDexEnabled true
+ // Multidex is not required for api level 21
}
buildTypes {
@@ -64,5 +64,4 @@ flutter {
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
- implementation 'com.android.support:multidex:1.0.3'
}
diff --git a/example/lib/main.dart b/example/lib/main.dart
index 1e71e94b..c4a44613 100644
--- a/example/lib/main.dart
+++ b/example/lib/main.dart
@@ -9,26 +9,13 @@ void main() {
}
class MyApp extends StatelessWidget {
- // This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Quill Demo',
theme: ThemeData(
- // This is the theme of your application.
- //
- // Try running your application with "flutter run". You'll see the
- // application has a blue toolbar. Then, without quitting the app, try
- // changing the primarySwatch below to Colors.green and then invoke
- // "hot reload" (press "r" in the console where you ran "flutter run",
- // or simply save your changes to "hot reload" in a Flutter IDE).
- // Notice that the counter didn't reset back to zero; the application
- // is not restarted.
primarySwatch: Colors.blue,
- // This makes the visual density adapt to the platform that you run
- // the app on. For desktop platforms, the controls will be smaller and
- // closer together (more dense) than on mobile platforms.
visualDensity: VisualDensity.adaptivePlatformDensity,
),
localizationsDelegates: [
diff --git a/example/lib/pages/home_page.dart b/example/lib/pages/home_page.dart
index 851491bb..c52369f1 100644
--- a/example/lib/pages/home_page.dart
+++ b/example/lib/pages/home_page.dart
@@ -11,7 +11,7 @@ import 'package:flutter/services.dart';
import 'package:flutter_quill/extensions.dart';
import 'package:flutter_quill/flutter_quill.dart' hide Text;
import 'package:flutter_quill_extensions/flutter_quill_extensions.dart';
-import 'package:path/path.dart';
+import 'package:path/path.dart' as path;
import 'package:path_provider/path_provider.dart';
import '../universal_ui/universal_ui.dart';
@@ -30,7 +30,8 @@ class HomePage extends StatefulWidget {
}
class _HomePageState extends State {
- QuillController? _controller;
+ late final QuillController _controller;
+ late final Future _loadDocumentFromAssetsFuture;
final FocusNode _focusNode = FocusNode();
Timer? _selectAllTimer;
_SelectionType _selectionType = _SelectionType.none;
@@ -38,13 +39,15 @@ class _HomePageState extends State {
@override
void dispose() {
_selectAllTimer?.cancel();
+ // Dispose the controller to free resources
+ _controller.dispose();
super.dispose();
}
@override
void initState() {
super.initState();
- _loadFromAssets();
+ _loadDocumentFromAssetsFuture = _loadFromAssets();
}
Future _loadFromAssets() async {
@@ -53,67 +56,73 @@ class _HomePageState extends State {
? 'assets/sample_data_nomedia.json'
: 'assets/sample_data.json');
final doc = Document.fromJson(jsonDecode(result));
- setState(() {
- _controller = QuillController(
- document: doc, selection: const TextSelection.collapsed(offset: 0));
- });
+ _controller = QuillController(
+ document: doc,
+ selection: const TextSelection.collapsed(offset: 0),
+ );
} catch (error) {
final doc = Document()..insert(0, 'Empty asset');
- setState(() {
- _controller = QuillController(
- document: doc, selection: const TextSelection.collapsed(offset: 0));
- });
+ _controller = QuillController(
+ document: doc,
+ selection: const TextSelection.collapsed(offset: 0),
+ );
}
}
@override
Widget build(BuildContext context) {
- if (_controller == null) {
- return const Scaffold(body: Center(child: Text('Loading...')));
- }
-
- return Scaffold(
- appBar: AppBar(
- backgroundColor: Colors.grey.shade800,
- elevation: 0,
- centerTitle: false,
- title: const Text(
- 'Flutter Quill',
- ),
- actions: [
- IconButton(
- onPressed: () => _insertTimeStamp(
- _controller!,
- DateTime.now().toString(),
+ return FutureBuilder(
+ future: _loadDocumentFromAssetsFuture,
+ builder: (context, snapshot) {
+ if (snapshot.connectionState == ConnectionState.waiting) {
+ return const Scaffold(
+ body: Center(child: CircularProgressIndicator.adaptive()),
+ );
+ }
+ return Scaffold(
+ appBar: AppBar(
+ backgroundColor: Colors.grey.shade800,
+ elevation: 0,
+ centerTitle: false,
+ title: const Text(
+ 'Flutter Quill',
),
- icon: const Icon(Icons.add_alarm_rounded),
- ),
- IconButton(
- onPressed: () => showDialog(
- context: context,
- builder: (context) => AlertDialog(
- content: Text(_controller!.document.toPlainText([
- ...FlutterQuillEmbeds.builders(),
- TimeStampEmbedBuilderWidget()
- ])),
+ actions: [
+ IconButton(
+ onPressed: () => _insertTimeStamp(
+ _controller,
+ DateTime.now().toString(),
+ ),
+ icon: const Icon(Icons.add_alarm_rounded),
),
- ),
- icon: const Icon(Icons.text_fields_rounded),
- )
- ],
- ),
- drawer: Container(
- constraints:
- BoxConstraints(maxWidth: MediaQuery.sizeOf(context).width * 0.7),
- color: Colors.grey.shade800,
- child: _buildMenuBar(context),
- ),
- body: _buildWelcomeEditor(context),
+ IconButton(
+ onPressed: () => showDialog(
+ context: context,
+ builder: (context) => AlertDialog(
+ content: Text(_controller.document.toPlainText([
+ ...FlutterQuillEmbeds.builders(),
+ TimeStampEmbedBuilderWidget()
+ ])),
+ ),
+ ),
+ icon: const Icon(Icons.text_fields_rounded),
+ )
+ ],
+ ),
+ drawer: Container(
+ constraints: BoxConstraints(
+ maxWidth: MediaQuery.sizeOf(context).width * 0.7),
+ color: Colors.grey.shade800,
+ child: _buildMenuBar(context),
+ ),
+ body: _buildWelcomeEditor(context),
+ );
+ },
);
}
bool _onTripleClickSelection() {
- final controller = _controller!;
+ final controller = _controller;
_selectAllTimer?.cancel();
_selectAllTimer = null;
@@ -174,9 +183,40 @@ class _HomePageState extends State {
});
}
- Widget _buildWelcomeEditor(BuildContext context) {
- Widget quillEditor = QuillEditor(
- controller: _controller!,
+ QuillEditor get quillEditor {
+ if (kIsWeb) {
+ return QuillEditor(
+ scrollController: ScrollController(),
+ scrollable: true,
+ focusNode: _focusNode,
+ autoFocus: false,
+ readOnly: false,
+ placeholder: 'Add content',
+ expands: false,
+ padding: EdgeInsets.zero,
+ onTapUp: (details, p1) {
+ return _onTripleClickSelection();
+ },
+ customStyles: const DefaultStyles(
+ h1: DefaultTextBlockStyle(
+ TextStyle(
+ fontSize: 32,
+ color: Colors.black,
+ height: 1.15,
+ fontWeight: FontWeight.w300,
+ ),
+ VerticalSpacing(16, 0),
+ VerticalSpacing(0, 0),
+ null),
+ sizeSmall: TextStyle(fontSize: 9),
+ ),
+ embedBuilders: [
+ ...defaultEmbedBuildersWeb,
+ TimeStampEmbedBuilderWidget()
+ ],
+ );
+ }
+ return QuillEditor(
scrollController: ScrollController(),
scrollable: true,
focusNode: _focusNode,
@@ -216,57 +256,11 @@ class _HomePageState extends State {
TimeStampEmbedBuilderWidget()
],
);
+ }
+
+ QuillToolbar get quillToolbar {
if (kIsWeb) {
- quillEditor = QuillEditor(
- controller: _controller!,
- scrollController: ScrollController(),
- scrollable: true,
- focusNode: _focusNode,
- autoFocus: false,
- readOnly: false,
- placeholder: 'Add content',
- expands: false,
- padding: EdgeInsets.zero,
- onTapUp: (details, p1) {
- return _onTripleClickSelection();
- },
- customStyles: const DefaultStyles(
- h1: DefaultTextBlockStyle(
- TextStyle(
- fontSize: 32,
- color: Colors.black,
- height: 1.15,
- fontWeight: FontWeight.w300,
- ),
- VerticalSpacing(16, 0),
- VerticalSpacing(0, 0),
- null),
- sizeSmall: TextStyle(fontSize: 9),
- ),
- embedBuilders: [
- ...defaultEmbedBuildersWeb,
- TimeStampEmbedBuilderWidget()
- ]);
- }
- var toolbar = QuillToolbar.basic(
- controller: _controller!,
- embedButtons: FlutterQuillEmbeds.buttons(
- // provide a callback to enable picking images from device.
- // if omit, "image" button only allows adding images from url.
- // same goes for videos.
- onImagePickCallback: _onImagePickCallback,
- onVideoPickCallback: _onVideoPickCallback,
- // uncomment to provide a custom "pick from" dialog.
- // mediaPickSettingSelector: _selectMediaPickSetting,
- // uncomment to provide a custom "pick from" dialog.
- // cameraPickSettingSelector: _selectCameraPickSetting,
- ),
- showAlignmentButtons: true,
- afterButtonPressed: _focusNode.requestFocus,
- );
- if (kIsWeb) {
- toolbar = QuillToolbar.basic(
- controller: _controller!,
+ return QuillToolbar.basic(
embedButtons: FlutterQuillEmbeds.buttons(
onImagePickCallback: _onImagePickCallback,
webImagePickImpl: _webImagePickImpl,
@@ -276,8 +270,7 @@ class _HomePageState extends State {
);
}
if (_isDesktop()) {
- toolbar = QuillToolbar.basic(
- controller: _controller!,
+ return QuillToolbar.basic(
embedButtons: FlutterQuillEmbeds.buttons(
onImagePickCallback: _onImagePickCallback,
filePickImpl: openFileSystemPickerForDesktop,
@@ -286,28 +279,78 @@ class _HomePageState extends State {
afterButtonPressed: _focusNode.requestFocus,
);
}
+ return QuillToolbar.basic(
+ embedButtons: FlutterQuillEmbeds.buttons(
+ // provide a callback to enable picking images from device.
+ // if omit, "image" button only allows adding images from url.
+ // same goes for videos.
+ onImagePickCallback: _onImagePickCallback,
+ onVideoPickCallback: _onVideoPickCallback,
+ // uncomment to provide a custom "pick from" dialog.
+ // mediaPickSettingSelector: _selectMediaPickSetting,
+ // uncomment to provide a custom "pick from" dialog.
+ // cameraPickSettingSelector: _selectCameraPickSetting,
+ ),
+ showAlignmentButtons: true,
+ afterButtonPressed: _focusNode.requestFocus,
+ );
+ }
+ Widget _buildWelcomeEditor(BuildContext context) {
+ // BUG in web!! should not releated to this pull request
+ ///
+ ///══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═════════════════════
+ ///══════════════════════════════════════
+ // The following bool object was thrown building MediaQuery
+ //(MediaQueryData(size: Size(769.0, 1205.0),
+ // devicePixelRatio: 1.0, textScaleFactor: 1.0, platformBrightness:
+ //Brightness.dark, padding:
+ // EdgeInsets.zero, viewPadding: EdgeInsets.zero, viewInsets:
+ // EdgeInsets.zero,
+ // systemGestureInsets:
+ // EdgeInsets.zero, alwaysUse24HourFormat: false, accessibleNavigation:
+ // false,
+ // highContrast: false,
+ // disableAnimations: false, invertColors: false, boldText: false,
+ //navigationMode: traditional,
+ // gestureSettings: DeviceGestureSettings(touchSlop: null), displayFeatures:
+ // []
+ // )):
+ // false
+ // The relevant error-causing widget was:
+ // SafeArea
+ ///
+ ///
return SafeArea(
- child: Column(
- mainAxisAlignment: MainAxisAlignment.spaceBetween,
- children: [
- Expanded(
- flex: 15,
- child: Container(
- color: Colors.white,
- padding: const EdgeInsets.only(left: 16, right: 16),
- child: quillEditor,
+ child: QuillProvider(
+ configurations: QuillConfigurations(
+ // (throw ArgumentError.checkNotNull(
+ // _controller,
+ // 'Quill controller',
+ // ))
+ controller: _controller,
+ ),
+ child: Column(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ Expanded(
+ flex: 15,
+ child: Container(
+ color: Colors.white,
+ padding: const EdgeInsets.only(left: 16, right: 16),
+ child: quillEditor,
+ ),
),
- ),
- kIsWeb
- ? Expanded(
- child: Container(
- padding:
- const EdgeInsets.symmetric(vertical: 16, horizontal: 8),
- child: toolbar,
- ))
- : Container(child: toolbar)
- ],
+ kIsWeb
+ ? Expanded(
+ child: Container(
+ padding:
+ const EdgeInsets.symmetric(vertical: 16, horizontal: 8),
+ child: quillToolbar,
+ ))
+ : Container(child: quillToolbar)
+ ],
+ ),
),
);
}
@@ -330,7 +373,7 @@ class _HomePageState extends State {
// Copies the picked file from temporary cache to applications directory
final appDocDir = await getApplicationDocumentsDirectory();
final copiedFile =
- await file.copy('${appDocDir.path}/${basename(file.path)}');
+ await file.copy('${appDocDir.path}/${path.basename(file.path)}');
return copiedFile.path.toString();
}
@@ -355,7 +398,7 @@ class _HomePageState extends State {
// Copies the picked file from temporary cache to applications directory
final appDocDir = await getApplicationDocumentsDirectory();
final copiedFile =
- await file.copy('${appDocDir.path}/${basename(file.path)}');
+ await file.copy('${appDocDir.path}/${path.basename(file.path)}');
return copiedFile.path.toString();
}
@@ -453,8 +496,8 @@ class _HomePageState extends State {
// Saves the image to applications directory
final appDocDir = await getApplicationDocumentsDirectory();
final file = await File(
- '${appDocDir.path}/${basename('${DateTime.now().millisecondsSinceEpoch}.png')}')
- .writeAsBytes(imageBytes, flush: true);
+ '${appDocDir.path}/${path.basename('${DateTime.now().millisecondsSinceEpoch}.png')}',
+ ).writeAsBytes(imageBytes, flush: true);
return file.path.toString();
}
diff --git a/example/lib/pages/read_only_page.dart b/example/lib/pages/read_only_page.dart
index d0ae032e..5f04b987 100644
--- a/example/lib/pages/read_only_page.dart
+++ b/example/lib/pages/read_only_page.dart
@@ -26,15 +26,15 @@ class _ReadOnlyPageState extends State {
builder: _buildContent,
showToolbar: _edit == true,
floatingActionButton: FloatingActionButton.extended(
- label: Text(_edit == true ? 'Done' : 'Edit'),
- onPressed: _toggleEdit,
- icon: Icon(_edit == true ? Icons.check : Icons.edit)),
+ label: Text(_edit == true ? 'Done' : 'Edit'),
+ onPressed: _toggleEdit,
+ icon: Icon(_edit == true ? Icons.check : Icons.edit),
+ ),
);
}
Widget _buildContent(BuildContext context, QuillController? controller) {
var quillEditor = QuillEditor(
- controller: controller!,
scrollController: ScrollController(),
scrollable: true,
focusNode: _focusNode,
@@ -46,7 +46,6 @@ class _ReadOnlyPageState extends State {
);
if (kIsWeb) {
quillEditor = QuillEditor(
- controller: controller,
scrollController: ScrollController(),
scrollable: true,
focusNode: _focusNode,
diff --git a/example/lib/widgets/demo_scaffold.dart b/example/lib/widgets/demo_scaffold.dart
index 93d38663..61cb8b10 100644
--- a/example/lib/widgets/demo_scaffold.dart
+++ b/example/lib/widgets/demo_scaffold.dart
@@ -84,45 +84,51 @@ class _DemoScaffoldState extends State {
);
}
+ QuillToolbar get quillToolbar {
+ if (_isDesktop()) {
+ return QuillToolbar.basic(
+ embedButtons: FlutterQuillEmbeds.buttons(
+ filePickImpl: openFileSystemPickerForDesktop,
+ ),
+ );
+ }
+ return QuillToolbar.basic(
+ embedButtons: FlutterQuillEmbeds.buttons(),
+ );
+ }
+
@override
Widget build(BuildContext context) {
if (_controller == null) {
return const Scaffold(body: Center(child: Text('Loading...')));
}
final actions = widget.actions ?? [];
- var toolbar = QuillToolbar.basic(
- controller: _controller!,
- embedButtons: FlutterQuillEmbeds.buttons(),
- );
- if (_isDesktop()) {
- toolbar = QuillToolbar.basic(
- controller: _controller!,
- embedButtons: FlutterQuillEmbeds.buttons(
- filePickImpl: openFileSystemPickerForDesktop),
- );
- }
- return Scaffold(
- key: _scaffoldKey,
- appBar: AppBar(
- elevation: 0,
- backgroundColor: Theme.of(context).canvasColor,
- centerTitle: false,
- titleSpacing: 0,
- leading: IconButton(
- icon: Icon(
- Icons.chevron_left,
- color: Colors.grey.shade800,
- size: 18,
+
+ return QuillProvider(
+ configurations: QuillConfigurations(controller: _controller!),
+ child: Scaffold(
+ key: _scaffoldKey,
+ appBar: AppBar(
+ elevation: 0,
+ backgroundColor: Theme.of(context).canvasColor,
+ centerTitle: false,
+ titleSpacing: 0,
+ leading: IconButton(
+ icon: Icon(
+ Icons.chevron_left,
+ color: Colors.grey.shade800,
+ size: 18,
+ ),
+ onPressed: () => Navigator.pop(context),
),
- onPressed: () => Navigator.pop(context),
+ title: _loading || !widget.showToolbar ? null : quillToolbar,
+ actions: actions,
),
- title: _loading || !widget.showToolbar ? null : toolbar,
- actions: actions,
+ floatingActionButton: widget.floatingActionButton,
+ body: _loading
+ ? const Center(child: Text('Loading...'))
+ : widget.builder(context, _controller),
),
- floatingActionButton: widget.floatingActionButton,
- body: _loading
- ? const Center(child: Text('Loading...'))
- : widget.builder(context, _controller),
);
}
diff --git a/example/macos/Podfile b/example/macos/Podfile
index dade8dfa..0c76ccf5 100644
--- a/example/macos/Podfile
+++ b/example/macos/Podfile
@@ -1,4 +1,4 @@
-platform :osx, '10.11'
+platform :osx, '12.0'
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
diff --git a/example/macos/Runner.xcodeproj/project.pbxproj b/example/macos/Runner.xcodeproj/project.pbxproj
index fa640cf1..29557646 100644
--- a/example/macos/Runner.xcodeproj/project.pbxproj
+++ b/example/macos/Runner.xcodeproj/project.pbxproj
@@ -3,7 +3,7 @@
archiveVersion = 1;
classes = {
};
- objectVersion = 51;
+ objectVersion = 54;
objects = {
/* Begin PBXAggregateTarget section */
@@ -21,12 +21,12 @@
/* End PBXAggregateTarget section */
/* Begin PBXBuildFile section */
+ 07D884DE6AB8033C3F60B238 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 48A88899E2BC5FD7AFD2B040 /* Pods_Runner.framework */; };
335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */; };
33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC10F02044A3C60003C045 /* AppDelegate.swift */; };
33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; };
33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; };
33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; };
- 7C7D9700842BA0E01048B7B5 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 93FCB7C0C7A612A19EB2D2C2 /* Pods_Runner.framework */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
@@ -53,7 +53,7 @@
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
- 0C1FD22CA47E09B485C5D2F0 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; };
+ 17BD0969A552CE47C17FC221 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; };
333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = ""; };
335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = ""; };
33CC10ED2044A3C60003C045 /* app.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = app.app; sourceTree = BUILT_PRODUCTS_DIR; };
@@ -68,11 +68,11 @@
33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = ""; };
33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = ""; };
33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = ""; };
- 4B8510D07EAD5FFD466A09A7 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; };
+ 3DB40E993F068140F6DEEA8F /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; };
+ 48A88899E2BC5FD7AFD2B040 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+ 676737A1C184536E1D9D90A1 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; };
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = ""; };
- 93FCB7C0C7A612A19EB2D2C2 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = ""; };
- F44289D50723316BB0B4ADA1 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@@ -80,7 +80,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
- 7C7D9700842BA0E01048B7B5 /* Pods_Runner.framework in Frameworks */,
+ 07D884DE6AB8033C3F60B238 /* Pods_Runner.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -104,8 +104,8 @@
33FAB671232836740065AC1E /* Runner */,
33CEB47122A05771004F2AC0 /* Flutter */,
33CC10EE2044A3C60003C045 /* Products */,
- D73912EC22F37F3D000D13A0 /* Frameworks */,
- D4C5240DF6823DEC9AB0AD3D /* Pods */,
+ E0CAA5D4D3AFCAEB94FF2464 /* Pods */,
+ C2525C9EE4B6956CB985C5A2 /* Frameworks */,
);
sourceTree = "";
};
@@ -152,23 +152,23 @@
path = Runner;
sourceTree = "";
};
- D4C5240DF6823DEC9AB0AD3D /* Pods */ = {
+ C2525C9EE4B6956CB985C5A2 /* Frameworks */ = {
isa = PBXGroup;
children = (
- 0C1FD22CA47E09B485C5D2F0 /* Pods-Runner.debug.xcconfig */,
- 4B8510D07EAD5FFD466A09A7 /* Pods-Runner.release.xcconfig */,
- F44289D50723316BB0B4ADA1 /* Pods-Runner.profile.xcconfig */,
+ 48A88899E2BC5FD7AFD2B040 /* Pods_Runner.framework */,
);
- name = Pods;
- path = Pods;
+ name = Frameworks;
sourceTree = "";
};
- D73912EC22F37F3D000D13A0 /* Frameworks */ = {
+ E0CAA5D4D3AFCAEB94FF2464 /* Pods */ = {
isa = PBXGroup;
children = (
- 93FCB7C0C7A612A19EB2D2C2 /* Pods_Runner.framework */,
+ 3DB40E993F068140F6DEEA8F /* Pods-Runner.debug.xcconfig */,
+ 676737A1C184536E1D9D90A1 /* Pods-Runner.release.xcconfig */,
+ 17BD0969A552CE47C17FC221 /* Pods-Runner.profile.xcconfig */,
);
- name = Frameworks;
+ name = Pods;
+ path = Pods;
sourceTree = "";
};
/* End PBXGroup section */
@@ -178,13 +178,13 @@
isa = PBXNativeTarget;
buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */;
buildPhases = (
- ECE07D1381B49CCA8A8E0C5F /* [CP] Check Pods Manifest.lock */,
+ 8E0B73589C7156B8D6C458C1 /* [CP] Check Pods Manifest.lock */,
33CC10E92044A3C60003C045 /* Sources */,
33CC10EA2044A3C60003C045 /* Frameworks */,
33CC10EB2044A3C60003C045 /* Resources */,
33CC110E2044A8840003C045 /* Bundle Framework */,
3399D490228B24CF009A79C7 /* ShellScript */,
- 678C02007C3A278E6325D529 /* [CP] Embed Pods Frameworks */,
+ 64BF2FA23C00365B5E3F66C0 /* [CP] Embed Pods Frameworks */,
);
buildRules = (
);
@@ -203,7 +203,7 @@
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 0920;
- LastUpgradeCheck = 0930;
+ LastUpgradeCheck = 1430;
ORGANIZATIONNAME = "";
TargetAttributes = {
33CC10EC2044A3C60003C045 = {
@@ -256,6 +256,7 @@
/* Begin PBXShellScriptBuildPhase section */
3399D490228B24CF009A79C7 /* ShellScript */ = {
isa = PBXShellScriptBuildPhase;
+ alwaysOutOfDate = 1;
buildActionMask = 2147483647;
files = (
);
@@ -291,7 +292,7 @@
shellPath = /bin/sh;
shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire";
};
- 678C02007C3A278E6325D529 /* [CP] Embed Pods Frameworks */ = {
+ 64BF2FA23C00365B5E3F66C0 /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
@@ -308,7 +309,7 @@
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
- ECE07D1381B49CCA8A8E0C5F /* [CP] Check Pods Manifest.lock */ = {
+ 8E0B73589C7156B8D6C458C1 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
@@ -404,7 +405,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
- MACOSX_DEPLOYMENT_TARGET = 10.11;
+ MACOSX_DEPLOYMENT_TARGET = "$(RECOMMENDED_MACOSX_DEPLOYMENT_TARGET)";
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = macosx;
SWIFT_COMPILATION_MODE = wholemodule;
@@ -426,6 +427,7 @@
"$(inherited)",
"@executable_path/../Frameworks",
);
+ MACOSX_DEPLOYMENT_TARGET = 12.0;
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_VERSION = 5.0;
};
@@ -483,7 +485,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
- MACOSX_DEPLOYMENT_TARGET = 10.11;
+ MACOSX_DEPLOYMENT_TARGET = "$(RECOMMENDED_MACOSX_DEPLOYMENT_TARGET)";
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = macosx;
@@ -530,7 +532,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
- MACOSX_DEPLOYMENT_TARGET = 10.11;
+ MACOSX_DEPLOYMENT_TARGET = "$(RECOMMENDED_MACOSX_DEPLOYMENT_TARGET)";
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = macosx;
SWIFT_COMPILATION_MODE = wholemodule;
@@ -552,6 +554,7 @@
"$(inherited)",
"@executable_path/../Frameworks",
);
+ MACOSX_DEPLOYMENT_TARGET = 12.0;
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
@@ -572,6 +575,7 @@
"$(inherited)",
"@executable_path/../Frameworks",
);
+ MACOSX_DEPLOYMENT_TARGET = 12.0;
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_VERSION = 5.0;
};
diff --git a/example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
index a462e330..8cbaa660 100644
--- a/example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
+++ b/example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
@@ -1,89 +1,89 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/example/pubspec.yaml b/example/pubspec.yaml
index 33b1e268..4053c2c7 100644
--- a/example/pubspec.yaml
+++ b/example/pubspec.yaml
@@ -1,20 +1,6 @@
name: app
description: demo app
-
-# The following line prevents the package from being accidentally published to
-# pub.dev using `pub publish`. This is preferred for private packages.
-publish_to: 'none' # Remove this line if you wish to publish to pub.dev
-
-# The following defines the version and build number for your application.
-# A version number is three numbers separated by dots, like 1.2.43
-# followed by an optional build number separated by a +.
-# Both the version and the builder number may be overridden in flutter
-# build by specifying --build-name and --build-number, respectively.
-# In Android, build-name is used as versionName while build-number used as versionCode.
-# Read more about Android versioning at https://developer.android.com/studio/publish/versioning
-# In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.
-# Read more about iOS versioning at
-# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
+publish_to: 'none'
version: 1.0.0+1
environment:
@@ -23,14 +9,12 @@ environment:
dependencies:
flutter:
sdk: flutter
- universal_html: ^2.0.8
+ universal_html: ^2.2.4
- # The following adds the Cupertino Icons font to your application.
- # Use with the CupertinoIcons class for iOS style icons.
- cupertino_icons: ^1.0.4
- path_provider: ^2.0.9
- filesystem_picker: ^3.1.0
- file_picker: ^5.2.2
+ cupertino_icons: ^1.0.6
+ path_provider: ^2.1.1
+ filesystem_picker: ^4.0.0
+ file_picker: ^6.0.0
flutter_quill:
path: ../
flutter_quill_extensions:
@@ -44,21 +28,9 @@ dev_dependencies:
flutter_test:
sdk: flutter
-# For information on the generic Dart part of this file, see the
-# following page: https://dart.dev/tools/pub/pubspec
-
-# The following section is specific to Flutter.
flutter:
- # The following line ensures that the Material Icons font is
- # included with your application, so that you can use the icons in
- # the material Icons class.
uses-material-design: true
-
- # To add assets to your application, add an assets section, like this:
- # assets:
- # - images/a_dot_burr.jpeg
- # - images/a_dot_ham.jpeg
assets:
- assets/
@@ -89,30 +61,4 @@ flutter:
- asset: assets/fonts/RobotoMono-Regular.ttf
- family: SF-UI-Display
fonts:
- - asset: assets/fonts/SF-Pro-Display-Regular.otf
-
- # An image asset can refer to one or more resolution-specific "variants", see
- # https://flutter.dev/assets-and-images/#resolution-aware.
-
- # For details regarding adding assets from package dependencies, see
- # https://flutter.dev/assets-and-images/#from-packages
-
- # To add custom fonts to your application, add a fonts section here,
- # in this "flutter" section. Each entry in this list should have a
- # "family" key with the font family name, and a "fonts" key with a
- # list giving the asset and other descriptors for the font. For
- # example:
- # fonts:
- # - family: Schyler
- # fonts:
- # - asset: fonts/Schyler-Regular.ttf
- # - asset: fonts/Schyler-Italic.ttf
- # style: italic
- # - family: Trajan Pro
- # fonts:
- # - asset: fonts/TrajanPro.ttf
- # - asset: fonts/TrajanPro_Bold.ttf
- # weight: 700
- #
- # For details regarding fonts from package dependencies,
- # see https://flutter.dev/custom-fonts/#from-packages
+ - asset: assets/fonts/SF-Pro-Display-Regular.otf
\ No newline at end of file
diff --git a/flutter_quill_extensions/pubspec.yaml b/flutter_quill_extensions/pubspec.yaml
index 7ec60cf0..83a3c069 100644
--- a/flutter_quill_extensions/pubspec.yaml
+++ b/flutter_quill_extensions/pubspec.yaml
@@ -3,6 +3,13 @@ description: Embed extensions for flutter_quill including image, video, formula
version: 0.5.1
homepage: https://bulletjournal.us/home/index.html
repository: https://github.com/singerdmx/flutter-quill/tree/master/flutter_quill_extensions
+platforms:
+ android:
+ ios:
+ # linux:
+ macos:
+ web:
+ windows:
environment:
sdk: ">=2.17.0 <4.0.0"
@@ -12,7 +19,7 @@ dependencies:
flutter:
sdk: flutter
- flutter_quill: ^7.4.15
+ flutter_quill: ^7.4.16
# In case you are working on changes for both libraries,
# flutter_quill:
# path: ~/development/playground/framework_based/flutter/flutter-quill
diff --git a/lib/flutter_quill.dart b/lib/flutter_quill.dart
index 22a0a20f..feee0e19 100644
--- a/lib/flutter_quill.dart
+++ b/lib/flutter_quill.dart
@@ -1,5 +1,6 @@
library flutter_quill;
+export 'src/core/quill_configurations.dart';
export 'src/models/documents/attribute.dart';
export 'src/models/documents/document.dart';
export 'src/models/documents/nodes/block.dart';
@@ -27,3 +28,4 @@ export 'src/widgets/link.dart' show LinkActionPickerDelegate, LinkMenuAction;
export 'src/widgets/style_widgets/style_widgets.dart';
export 'src/widgets/toolbar.dart';
export 'src/widgets/toolbar/enum.dart';
+export 'src/widgets/utils/provider.dart';
diff --git a/lib/src/core/quill_configurations.dart b/lib/src/core/quill_configurations.dart
new file mode 100644
index 00000000..68eef5b1
--- /dev/null
+++ b/lib/src/core/quill_configurations.dart
@@ -0,0 +1,54 @@
+import 'package:flutter/foundation.dart' show immutable;
+import 'package:flutter/material.dart' show Color, Colors;
+
+import '../../flutter_quill.dart';
+
+// I will start on this in the major-update-2
+
+@immutable
+class QuillToolbarConfigurations {
+ const QuillToolbarConfigurations();
+}
+
+///
+@immutable
+class QuillEditorConfigurations {
+ const QuillEditorConfigurations();
+}
+
+/// The shared configurations between [QuillEditorConfigurations] and
+/// [QuillToolbarConfigurations] so we don't duplicate things
+class QuillSharedConfigurations {
+ const QuillSharedConfigurations({
+ this.dialogBarrierColor = Colors.black54,
+ });
+
+ // This is just example or showcase of this major update to make the library
+ // more maintanable, flexible, and customizable
+ /// The barrier color of the shown dialogs
+ final Color dialogBarrierColor;
+}
+
+@immutable
+class QuillConfigurations {
+ const QuillConfigurations({
+ required this.controller,
+ this.editorConfigurations = const QuillEditorConfigurations(),
+ this.toolbarConfigurations = const QuillToolbarConfigurations(),
+ this.sharedConfigurations = const QuillSharedConfigurations(),
+ });
+
+ /// Controller object which establishes a link between a rich text document
+ /// and this editor.
+ ///
+ /// The controller is shared between [QuillEditorConfigurations] and
+ /// [QuillToolbarConfigurations] but to simplify things we will defined it
+ /// here, it should not be null
+ final QuillController controller;
+
+ final QuillEditorConfigurations editorConfigurations;
+
+ final QuillToolbarConfigurations toolbarConfigurations;
+
+ final QuillSharedConfigurations sharedConfigurations;
+}
diff --git a/lib/src/models/documents/nodes/container.dart b/lib/src/models/documents/nodes/container.dart
index c8cd3a59..f061a4ca 100644
--- a/lib/src/models/documents/nodes/container.dart
+++ b/lib/src/models/documents/nodes/container.dart
@@ -12,7 +12,8 @@ import 'node.dart';
/// operation container looks for a child at specified index position and
/// forwards operation to that child.
///
-/// Most of the operation handling logic is implemented by [Line] and [Text].
+/// Most of the operation handling logic is implemented by [Line]
+/// and [QuillText].
abstract class Container extends Node {
final LinkedList _children = LinkedList();
diff --git a/lib/src/models/documents/nodes/leaf.dart b/lib/src/models/documents/nodes/leaf.dart
index 8f8b13a7..556590bc 100644
--- a/lib/src/models/documents/nodes/leaf.dart
+++ b/lib/src/models/documents/nodes/leaf.dart
@@ -16,12 +16,12 @@ abstract class Leaf extends Node {
}
final text = data as String;
assert(text.isNotEmpty);
- return Text(text);
+ return QuillText(text);
}
Leaf.val(Object val) : _value = val;
- /// Contents of this node, either a String if this is a [Text] or an
+ /// Contents of this node, either a String if this is a [QuillText] or an
/// [Embed] if this is an [BlockEmbed].
Object get value => _value;
Object _value;
@@ -119,11 +119,11 @@ abstract class Leaf extends Node {
}
// This is a text node and it can only be merged with other text nodes.
- var node = this as Text;
+ var node = this as QuillText;
// Merging it with previous node if style is the same.
final prev = node.previous;
- if (!node.isFirst && prev is Text && prev.style == node.style) {
+ if (!node.isFirst && prev is QuillText && prev.style == node.style) {
prev._value = prev.value + node.value;
node.unlink();
node = prev;
@@ -131,7 +131,7 @@ abstract class Leaf extends Node {
// Merging it with next node if style is the same.
final next = node.next;
- if (!node.isLast && next is Text && next.style == node.style) {
+ if (!node.isLast && next is QuillText && next.style == node.style) {
node._value = node.value + next.value;
next.unlink();
}
@@ -157,7 +157,7 @@ abstract class Leaf extends Node {
return isLast ? null : next as Leaf?;
}
- assert(this is Text);
+ assert(this is QuillText);
final text = _value as String;
_value = text.substring(0, index);
final split = Leaf(text.substring(index))..applyStyle(style);
@@ -200,6 +200,9 @@ abstract class Leaf extends Node {
}
}
+@Deprecated('Please use [QuillText] instead')
+class Text extends QuillText {}
+
/// A span of formatted text within a line in a Quill document.
///
/// Text is a leaf node of a document tree.
@@ -211,13 +214,18 @@ abstract class Leaf extends Node {
///
/// * [Embed], a leaf node representing an embeddable object.
/// * [Line], a node representing a line of text.
-class Text extends Leaf {
- Text([String text = ''])
+///
+/// Update:
+/// The reason we are renamed quill Text to [QuillText] so it doesn't
+/// conflict with the one from the widgets, material or cupertino library
+///
+class QuillText extends Leaf {
+ QuillText([String text = ''])
: assert(!text.contains('\n')),
super.val(text);
@override
- Node newInstance() => Text(value);
+ Node newInstance() => QuillText(value);
@override
String get value => _value as String;
@@ -232,7 +240,7 @@ class Text extends Leaf {
/// An embed node inside of a line in a Quill document.
///
-/// Embed node is a leaf node similar to [Text]. It represents an arbitrary
+/// Embed node is a leaf node similar to [QuillText]. It represents an arbitrary
/// piece of non-textual content embedded into a document, such as, image,
/// horizontal rule, video, or any other object with defined structure,
/// like a tweet, for instance.
diff --git a/lib/src/models/documents/nodes/line.dart b/lib/src/models/documents/nodes/line.dart
index 724425a4..b34f00fa 100644
--- a/lib/src/models/documents/nodes/line.dart
+++ b/lib/src/models/documents/nodes/line.dart
@@ -15,13 +15,13 @@ import 'node.dart';
/// A line of rich text in a Quill document.
///
-/// Line serves as a container for [Leaf]s, like [Text] and [Embed].
+/// Line serves as a container for [Leaf]s, like [QuillText] and [Embed].
///
/// When a line contains an embed, it fully occupies the line, no other embeds
/// or text nodes are allowed.
class Line extends Container {
@override
- Leaf get defaultChild => Text();
+ Leaf get defaultChild => QuillText();
@override
int get length => super.length + 1;
@@ -400,14 +400,14 @@ class Line extends Container {
if (node != null) {
var pos = 0;
pos = node.length - data.offset;
- if (node is Text && node.style.isNotEmpty) {
+ if (node is QuillText && node.style.isNotEmpty) {
result.add(OffsetValue(beg, node.style, node.length));
} else if (node.value is Embeddable) {
result.add(OffsetValue(beg, node.value as Embeddable, node.length));
}
while (!node!.isLast && pos < local) {
node = node.next as Leaf;
- if (node is Text && node.style.isNotEmpty) {
+ if (node is QuillText && node.style.isNotEmpty) {
result.add(OffsetValue(pos + beg, node.style, node.length));
} else if (node.value is Embeddable) {
result.add(
diff --git a/lib/src/test/widget_tester_extension.dart b/lib/src/test/widget_tester_extension.dart
index 21bb75ab..866c5c7f 100644
--- a/lib/src/test/widget_tester_extension.dart
+++ b/lib/src/test/widget_tester_extension.dart
@@ -2,7 +2,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import '../widgets/editor.dart';
-import '../widgets/raw_editor.dart';
+import '../widgets/raw_editor/raw_editor.dart';
/// Extends
extension QuillEnterText on WidgetTester {
diff --git a/lib/src/utils/extensions/build_context.dart b/lib/src/utils/extensions/build_context.dart
new file mode 100644
index 00000000..2df233ab
--- /dev/null
+++ b/lib/src/utils/extensions/build_context.dart
@@ -0,0 +1,37 @@
+import 'package:flutter/widgets.dart' show BuildContext;
+
+import '../../../flutter_quill.dart';
+
+extension BuildContextExt on BuildContext {
+ QuillProvider get requireQuillProvider {
+ return QuillProvider.ofNotNull(this);
+ }
+
+ QuillProvider? get quillProvider {
+ return QuillProvider.of(this);
+ }
+
+ QuillController? get quilController {
+ return quillProvider?.configurations.controller;
+ }
+
+ QuillController get requireQuillController {
+ return requireQuillProvider.configurations.controller;
+ }
+
+ QuillConfigurations get requireQuillConfigurations {
+ return requireQuillProvider.configurations;
+ }
+
+ QuillConfigurations? get quillConfigurations {
+ return quillProvider?.configurations;
+ }
+
+ QuillSharedConfigurations? get sharedQuillConfigurations {
+ return quillConfigurations?.sharedConfigurations;
+ }
+
+ QuillSharedConfigurations get requireSharedQuillConfigurations {
+ return requireQuillConfigurations.sharedConfigurations;
+ }
+}
diff --git a/lib/src/widgets/editor.dart b/lib/src/widgets/editor.dart
index 690fbd5d..80c34db5 100644
--- a/lib/src/widgets/editor.dart
+++ b/lib/src/widgets/editor.dart
@@ -11,21 +11,16 @@ import 'package:flutter/rendering.dart';
import 'package:flutter/services.dart';
import 'package:i18n_extension/i18n_widget.dart';
-import '../models/documents/document.dart';
+import '../../flutter_quill.dart';
import '../models/documents/nodes/container.dart' as container_node;
-import '../models/documents/nodes/leaf.dart';
-import '../models/structs/offset_value.dart';
-import '../models/themes/quill_dialog_theme.dart';
+import '../utils/extensions/build_context.dart';
import '../utils/platform.dart';
import 'box.dart';
-import 'controller.dart';
import 'cursor.dart';
-import 'default_styles.dart';
import 'delegate.dart';
-import 'embeds.dart';
import 'float_cursor.dart';
import 'link.dart';
-import 'raw_editor.dart';
+import 'raw_editor/raw_editor.dart';
import 'text_selection.dart';
/// Base interface for the editor state which defines contract used by
@@ -148,7 +143,6 @@ abstract class RenderAbstractEditor implements TextLayoutMetrics {
class QuillEditor extends StatefulWidget {
const QuillEditor({
- required this.controller,
required this.focusNode,
required this.scrollController,
required this.scrollable,
@@ -198,7 +192,6 @@ class QuillEditor extends StatefulWidget {
}) : super(key: key);
factory QuillEditor.basic({
- required QuillController controller,
required bool readOnly,
TextSelectionThemeData? textSelectionThemeData,
Brightness? keyboardAppearance,
@@ -215,7 +208,6 @@ class QuillEditor extends StatefulWidget {
Locale? locale,
}) {
return QuillEditor(
- controller: controller,
scrollController: ScrollController(),
scrollable: true,
focusNode: focusNode ?? FocusNode(),
@@ -232,11 +224,7 @@ class QuillEditor extends StatefulWidget {
);
}
- /// Controller object which establishes a link between a rich text document
- /// and this editor.
- ///
- /// Must not be null.
- final QuillController controller;
+ // final QuillController controller;
/// Controls whether this editor has keyboard focus.
final FocusNode focusNode;
@@ -523,7 +511,7 @@ class QuillEditorState extends State
final child = RawEditor(
key: _editorKey,
- controller: widget.controller,
+ controller: context.requireQuillController,
focusNode: widget.focusNode,
scrollController: widget.scrollController,
scrollable: widget.scrollable,
@@ -692,7 +680,7 @@ class _QuillEditorSelectionGestureDetectorBuilder
}
bool _isPositionSelected(TapUpDetails details) {
- if (_state.widget.controller.document.isEmpty()) {
+ if (_state.context.requireQuillController.document.isEmpty()) {
return false;
}
final pos = renderEditor!.getPositionForOffset(details.globalPosition);
@@ -705,7 +693,9 @@ class _QuillEditorSelectionGestureDetectorBuilder
final segmentLeaf = result.leaf;
if (segmentLeaf == null && line.length == 1) {
editor!.widget.controller.updateSelection(
- TextSelection.collapsed(offset: pos.offset), ChangeSource.LOCAL);
+ TextSelection.collapsed(offset: pos.offset),
+ ChangeSource.LOCAL,
+ );
return true;
}
return false;
diff --git a/lib/src/widgets/raw_editor.dart b/lib/src/widgets/raw_editor/raw_editor.dart
similarity index 98%
rename from lib/src/widgets/raw_editor.dart
rename to lib/src/widgets/raw_editor/raw_editor.dart
index 71229eef..a43320dd 100644
--- a/lib/src/widgets/raw_editor.dart
+++ b/lib/src/widgets/raw_editor/raw_editor.dart
@@ -24,36 +24,36 @@ import 'package:flutter_keyboard_visibility/flutter_keyboard_visibility.dart'
show KeyboardVisibilityController;
import 'package:pasteboard/pasteboard.dart' show Pasteboard;
-import '../models/documents/attribute.dart';
-import '../models/documents/document.dart';
-import '../models/documents/nodes/block.dart';
-import '../models/documents/nodes/embeddable.dart';
-import '../models/documents/nodes/leaf.dart' as leaf;
-import '../models/documents/nodes/line.dart';
-import '../models/documents/nodes/node.dart';
-import '../models/structs/offset_value.dart';
-import '../models/structs/vertical_spacing.dart';
-import '../models/themes/quill_dialog_theme.dart';
-import '../utils/cast.dart';
-import '../utils/delta.dart';
-import '../utils/embeds.dart';
-import '../utils/platform.dart';
-import 'controller.dart';
-import 'cursor.dart';
-import 'default_styles.dart';
-import 'delegate.dart';
-import 'editor.dart';
-import 'keyboard_listener.dart';
-import 'link.dart';
-import 'proxy.dart';
-import 'quill_single_child_scroll_view.dart';
-import 'raw_editor/raw_editor_state_selection_delegate_mixin.dart';
-import 'raw_editor/raw_editor_state_text_input_client_mixin.dart';
-import 'text_block.dart';
-import 'text_line.dart';
-import 'text_selection.dart';
-import 'toolbar/link_style_button2.dart';
-import 'toolbar/search_dialog.dart';
+import '../../models/documents/attribute.dart';
+import '../../models/documents/document.dart';
+import '../../models/documents/nodes/block.dart';
+import '../../models/documents/nodes/embeddable.dart';
+import '../../models/documents/nodes/leaf.dart' as leaf;
+import '../../models/documents/nodes/line.dart';
+import '../../models/documents/nodes/node.dart';
+import '../../models/structs/offset_value.dart';
+import '../../models/structs/vertical_spacing.dart';
+import '../../models/themes/quill_dialog_theme.dart';
+import '../../utils/cast.dart';
+import '../../utils/delta.dart';
+import '../../utils/embeds.dart';
+import '../../utils/platform.dart';
+import '../controller.dart';
+import '../cursor.dart';
+import '../default_styles.dart';
+import '../delegate.dart';
+import '../editor.dart';
+import '../keyboard_listener.dart';
+import '../link.dart';
+import '../proxy.dart';
+import '../quill_single_child_scroll_view.dart';
+import '../text_block.dart';
+import '../text_line.dart';
+import '../text_selection.dart';
+import '../toolbar/link_style_button2.dart';
+import '../toolbar/search_dialog.dart';
+import 'raw_editor_state_selection_delegate_mixin.dart';
+import 'raw_editor_state_text_input_client_mixin.dart';
class RawEditor extends StatefulWidget {
const RawEditor({
@@ -749,7 +749,7 @@ class RawEditorState extends EditorState
return KeyEventResult.ignored;
}
- final text = castOrNull(line.first);
+ final text = castOrNull(line.first);
if (text == null) {
return KeyEventResult.ignored;
}
@@ -805,7 +805,7 @@ class RawEditorState extends EditorState
return insertTabCharacter();
}
- if (node is! Line || (node.isNotEmpty && node.first is! leaf.Text)) {
+ if (node is! Line || (node.isNotEmpty && node.first is! leaf.QuillText)) {
return insertTabCharacter();
}
@@ -814,7 +814,7 @@ class RawEditorState extends EditorState
parentBlock.style.containsKey(Attribute.ul.key) ||
parentBlock.style.containsKey(Attribute.checked.key)) {
if (node.isNotEmpty &&
- (node.first as leaf.Text).value.isNotEmpty &&
+ (node.first as leaf.QuillText).value.isNotEmpty &&
controller.selection.base.offset > node.documentOffset) {
return insertTabCharacter();
}
@@ -822,7 +822,7 @@ class RawEditorState extends EditorState
return KeyEventResult.handled;
}
- if (node.isNotEmpty && (node.first as leaf.Text).value.isNotEmpty) {
+ if (node.isNotEmpty && (node.first as leaf.QuillText).value.isNotEmpty) {
return insertTabCharacter();
}
diff --git a/lib/src/widgets/text_line.dart b/lib/src/widgets/text_line.dart
index 9358777a..6dd4f793 100644
--- a/lib/src/widgets/text_line.dart
+++ b/lib/src/widgets/text_line.dart
@@ -240,7 +240,7 @@ class _TextLineState extends State {
TextSpan _buildTextSpan(DefaultStyles defaultStyles, LinkedList nodes,
TextStyle lineStyle) {
if (nodes.isEmpty && kIsWeb) {
- nodes = LinkedList()..add(leaf.Text('\u{200B}'));
+ nodes = LinkedList()..add(leaf.QuillText('\u{200B}'));
}
final children = nodes
.map((node) =>
@@ -307,7 +307,7 @@ class _TextLineState extends State {
TextSpan _getTextSpanFromNode(
DefaultStyles defaultStyles, Node node, Style lineStyle) {
- final textNode = node as leaf.Text;
+ final textNode = node as leaf.QuillText;
final nodeStyle = textNode.style;
final isLink = nodeStyle.containsKey(Attribute.link.key) &&
nodeStyle.attributes[Attribute.link.key]!.value != null;
@@ -323,8 +323,12 @@ class _TextLineState extends State {
);
}
- TextStyle _getInlineTextStyle(leaf.Text textNode, DefaultStyles defaultStyles,
- Style nodeStyle, Style lineStyle, bool isLink) {
+ TextStyle _getInlineTextStyle(
+ leaf.QuillText textNode,
+ DefaultStyles defaultStyles,
+ Style nodeStyle,
+ Style lineStyle,
+ bool isLink) {
var res = const TextStyle(); // This is inline text style
final color = textNode.style.attributes[Attribute.color.key];
@@ -413,7 +417,7 @@ class _TextLineState extends State {
}
if (widget.customRecognizerBuilder != null) {
- final textNode = segment as leaf.Text;
+ final textNode = segment as leaf.QuillText;
final nodeStyle = textNode.style;
nodeStyle.attributes.forEach((key, value) {
@@ -1097,7 +1101,7 @@ class RenderEditableTextLine extends RenderEditableBox {
if (inlineCodeStyle.backgroundColor != null) {
for (final item in line.children) {
- if (item is! leaf.Text ||
+ if (item is! leaf.QuillText ||
!item.style.containsKey(Attribute.inlineCode.key)) {
continue;
}
diff --git a/lib/src/widgets/toolbar.dart b/lib/src/widgets/toolbar.dart
index 2ea62fe6..ea9be6a9 100644
--- a/lib/src/widgets/toolbar.dart
+++ b/lib/src/widgets/toolbar.dart
@@ -1,29 +1,10 @@
import 'package:flutter/material.dart';
import 'package:i18n_extension/i18n_widget.dart';
-import '../models/documents/attribute.dart';
-import '../models/structs/link_dialog_action.dart';
-import '../models/themes/quill_custom_button.dart';
-import '../models/themes/quill_dialog_theme.dart';
-import '../models/themes/quill_icon_theme.dart';
+import '../../flutter_quill.dart';
import '../translations/toolbar.i18n.dart';
-import 'controller.dart';
-import 'embeds.dart';
+import '../utils/extensions/build_context.dart';
import 'toolbar/arrow_indicated_button_list.dart';
-import 'toolbar/clear_format_button.dart';
-import 'toolbar/color_button.dart';
-import 'toolbar/custom_button.dart';
-import 'toolbar/enum.dart';
-import 'toolbar/history_button.dart';
-import 'toolbar/indent_button.dart';
-import 'toolbar/link_style_button.dart';
-import 'toolbar/quill_font_family_button.dart';
-import 'toolbar/quill_font_size_button.dart';
-import 'toolbar/search_button.dart';
-import 'toolbar/select_alignment_button.dart';
-import 'toolbar/select_header_style_button.dart';
-import 'toolbar/toggle_check_list_button.dart';
-import 'toolbar/toggle_style_button.dart';
export 'toolbar/clear_format_button.dart';
export 'toolbar/color_button.dart';
@@ -50,9 +31,13 @@ const double kIconButtonFactor = 1.77;
/// The horizontal margin between the contents of each toolbar section.
const double kToolbarSectionSpacing = 4;
+typedef QuillToolbarChildrenBuilder = List Function(
+ BuildContext context,
+);
+
class QuillToolbar extends StatelessWidget implements PreferredSizeWidget {
const QuillToolbar({
- required this.children,
+ required this.childrenBuilder,
this.axis = Axis.horizontal,
this.toolbarSize = kDefaultIconSize * 2,
this.toolbarSectionSpacing = kToolbarSectionSpacing,
@@ -71,7 +56,6 @@ class QuillToolbar extends StatelessWidget implements PreferredSizeWidget {
}) : super(key: key);
factory QuillToolbar.basic({
- required QuillController controller,
Axis axis = Axis.horizontal,
double toolbarIconSize = kDefaultIconSize,
double toolbarSectionSpacing = kToolbarSectionSpacing,
@@ -261,349 +245,370 @@ class QuillToolbar extends StatelessWidget implements PreferredSizeWidget {
customButtons: customButtons,
locale: locale,
afterButtonPressed: afterButtonPressed,
- children: [
- if (showUndo)
- HistoryButton(
- icon: Icons.undo_outlined,
- iconSize: toolbarIconSize,
- tooltip: buttonTooltips[ToolbarButtons.undo],
- controller: controller,
- undo: true,
- iconTheme: iconTheme,
- afterButtonPressed: afterButtonPressed,
- ),
- if (showRedo)
- HistoryButton(
- icon: Icons.redo_outlined,
- iconSize: toolbarIconSize,
- tooltip: buttonTooltips[ToolbarButtons.redo],
- controller: controller,
- undo: false,
- iconTheme: iconTheme,
- afterButtonPressed: afterButtonPressed,
- ),
- if (showFontFamily)
- QuillFontFamilyButton(
- iconTheme: iconTheme,
- iconSize: toolbarIconSize,
- tooltip: buttonTooltips[ToolbarButtons.fontFamily],
- attribute: Attribute.font,
- controller: controller,
- rawItemsMap: fontFamilies,
- afterButtonPressed: afterButtonPressed,
- ),
- if (showFontSize)
- QuillFontSizeButton(
- iconTheme: iconTheme,
- iconSize: toolbarIconSize,
- tooltip: buttonTooltips[ToolbarButtons.fontSize],
- attribute: Attribute.size,
- controller: controller,
- rawItemsMap: fontSizes,
- afterButtonPressed: afterButtonPressed,
- ),
- if (showBoldButton)
- ToggleStyleButton(
- attribute: Attribute.bold,
- icon: Icons.format_bold,
- iconSize: toolbarIconSize,
- tooltip: buttonTooltips[ToolbarButtons.bold],
- controller: controller,
- iconTheme: iconTheme,
- afterButtonPressed: afterButtonPressed,
- ),
- if (showSubscript)
- ToggleStyleButton(
- attribute: Attribute.subscript,
- icon: Icons.subscript,
- iconSize: toolbarIconSize,
- tooltip: buttonTooltips[ToolbarButtons.subscript],
- controller: controller,
- iconTheme: iconTheme,
- afterButtonPressed: afterButtonPressed,
- ),
- if (showSuperscript)
- ToggleStyleButton(
- attribute: Attribute.superscript,
- icon: Icons.superscript,
- iconSize: toolbarIconSize,
- tooltip: buttonTooltips[ToolbarButtons.superscript],
- controller: controller,
- iconTheme: iconTheme,
- afterButtonPressed: afterButtonPressed,
- ),
- if (showItalicButton)
- ToggleStyleButton(
- attribute: Attribute.italic,
- icon: Icons.format_italic,
- iconSize: toolbarIconSize,
- tooltip: buttonTooltips[ToolbarButtons.italic],
- controller: controller,
- iconTheme: iconTheme,
- afterButtonPressed: afterButtonPressed,
- ),
- if (showSmallButton)
- ToggleStyleButton(
- attribute: Attribute.small,
- icon: Icons.format_size,
- iconSize: toolbarIconSize,
- tooltip: buttonTooltips[ToolbarButtons.small],
- controller: controller,
- iconTheme: iconTheme,
- afterButtonPressed: afterButtonPressed,
- ),
- if (showUnderLineButton)
- ToggleStyleButton(
- attribute: Attribute.underline,
- icon: Icons.format_underline,
- iconSize: toolbarIconSize,
- tooltip: buttonTooltips[ToolbarButtons.underline],
- controller: controller,
- iconTheme: iconTheme,
- afterButtonPressed: afterButtonPressed,
- ),
- if (showStrikeThrough)
- ToggleStyleButton(
- attribute: Attribute.strikeThrough,
- icon: Icons.format_strikethrough,
- iconSize: toolbarIconSize,
- tooltip: buttonTooltips[ToolbarButtons.strikeThrough],
- controller: controller,
- iconTheme: iconTheme,
- afterButtonPressed: afterButtonPressed,
- ),
- if (showInlineCode)
- ToggleStyleButton(
- attribute: Attribute.inlineCode,
- icon: Icons.code,
- iconSize: toolbarIconSize,
- tooltip: buttonTooltips[ToolbarButtons.inlineCode],
- controller: controller,
- iconTheme: iconTheme,
- afterButtonPressed: afterButtonPressed,
- ),
- if (showColorButton)
- ColorButton(
- icon: Icons.color_lens,
- iconSize: toolbarIconSize,
- tooltip: buttonTooltips[ToolbarButtons.color],
- controller: controller,
- background: false,
- iconTheme: iconTheme,
- afterButtonPressed: afterButtonPressed,
- ),
- if (showBackgroundColorButton)
- ColorButton(
- icon: Icons.format_color_fill,
- iconSize: toolbarIconSize,
- tooltip: buttonTooltips[ToolbarButtons.backgroundColor],
- controller: controller,
- background: true,
- iconTheme: iconTheme,
- afterButtonPressed: afterButtonPressed,
- ),
- if (showClearFormat)
- ClearFormatButton(
- icon: Icons.format_clear,
- iconSize: toolbarIconSize,
- tooltip: buttonTooltips[ToolbarButtons.clearFormat],
- controller: controller,
- iconTheme: iconTheme,
- afterButtonPressed: afterButtonPressed,
- ),
- if (embedButtons != null)
- for (final builder in embedButtons)
- builder(controller, toolbarIconSize, iconTheme, dialogTheme),
- if (showDividers &&
- isButtonGroupShown[0] &&
- (isButtonGroupShown[1] ||
- isButtonGroupShown[2] ||
- isButtonGroupShown[3] ||
- isButtonGroupShown[4] ||
- isButtonGroupShown[5]))
- QuillDivider(axis,
- color: sectionDividerColor, space: sectionDividerSpace),
- if (showAlignmentButtons)
- SelectAlignmentButton(
- controller: controller,
- tooltips: Map.of(buttonTooltips)
- ..removeWhere((key, value) => ![
- ToolbarButtons.leftAlignment,
- ToolbarButtons.centerAlignment,
- ToolbarButtons.rightAlignment,
- ToolbarButtons.justifyAlignment,
- ].contains(key)),
- iconSize: toolbarIconSize,
- iconTheme: iconTheme,
- showLeftAlignment: showLeftAlignment,
- showCenterAlignment: showCenterAlignment,
- showRightAlignment: showRightAlignment,
- showJustifyAlignment: showJustifyAlignment,
- afterButtonPressed: afterButtonPressed,
- ),
- if (showDirection)
- ToggleStyleButton(
- attribute: Attribute.rtl,
- tooltip: buttonTooltips[ToolbarButtons.direction],
- controller: controller,
- icon: Icons.format_textdirection_r_to_l,
- iconSize: toolbarIconSize,
- iconTheme: iconTheme,
- afterButtonPressed: afterButtonPressed,
- ),
- if (showDividers &&
- isButtonGroupShown[1] &&
- (isButtonGroupShown[2] ||
- isButtonGroupShown[3] ||
- isButtonGroupShown[4] ||
- isButtonGroupShown[5]))
- QuillDivider(axis,
- color: sectionDividerColor, space: sectionDividerSpace),
- if (showHeaderStyle)
- SelectHeaderStyleButton(
- tooltip: buttonTooltips[ToolbarButtons.headerStyle],
- controller: controller,
- axis: axis,
- iconSize: toolbarIconSize,
- iconTheme: iconTheme,
- afterButtonPressed: afterButtonPressed,
- ),
- if (showDividers &&
- showHeaderStyle &&
- isButtonGroupShown[2] &&
- (isButtonGroupShown[3] ||
- isButtonGroupShown[4] ||
- isButtonGroupShown[5]))
- QuillDivider(axis,
- color: sectionDividerColor, space: sectionDividerSpace),
- if (showListNumbers)
- ToggleStyleButton(
- attribute: Attribute.ol,
- tooltip: buttonTooltips[ToolbarButtons.listNumbers],
- controller: controller,
- icon: Icons.format_list_numbered,
- iconSize: toolbarIconSize,
- iconTheme: iconTheme,
- afterButtonPressed: afterButtonPressed,
- ),
- if (showListBullets)
- ToggleStyleButton(
- attribute: Attribute.ul,
- tooltip: buttonTooltips[ToolbarButtons.listBullets],
- controller: controller,
- icon: Icons.format_list_bulleted,
- iconSize: toolbarIconSize,
- iconTheme: iconTheme,
- afterButtonPressed: afterButtonPressed,
- ),
- if (showListCheck)
- ToggleCheckListButton(
- attribute: Attribute.unchecked,
- tooltip: buttonTooltips[ToolbarButtons.listChecks],
- controller: controller,
- icon: Icons.check_box,
- iconSize: toolbarIconSize,
- iconTheme: iconTheme,
- afterButtonPressed: afterButtonPressed,
- ),
- if (showCodeBlock)
- ToggleStyleButton(
- attribute: Attribute.codeBlock,
- tooltip: buttonTooltips[ToolbarButtons.codeBlock],
- controller: controller,
- icon: Icons.code,
- iconSize: toolbarIconSize,
- iconTheme: iconTheme,
- afterButtonPressed: afterButtonPressed,
- ),
- if (showDividers &&
- isButtonGroupShown[3] &&
- (isButtonGroupShown[4] || isButtonGroupShown[5]))
- QuillDivider(axis,
- color: sectionDividerColor, space: sectionDividerSpace),
- if (showQuote)
- ToggleStyleButton(
- attribute: Attribute.blockQuote,
- tooltip: buttonTooltips[ToolbarButtons.quote],
- controller: controller,
- icon: Icons.format_quote,
- iconSize: toolbarIconSize,
- iconTheme: iconTheme,
- afterButtonPressed: afterButtonPressed,
- ),
- if (showIndent)
- IndentButton(
- icon: Icons.format_indent_increase,
- iconSize: toolbarIconSize,
- tooltip: buttonTooltips[ToolbarButtons.indentIncrease],
- controller: controller,
- isIncrease: true,
- iconTheme: iconTheme,
- afterButtonPressed: afterButtonPressed,
- ),
- if (showIndent)
- IndentButton(
- icon: Icons.format_indent_decrease,
- iconSize: toolbarIconSize,
- tooltip: buttonTooltips[ToolbarButtons.indentDecrease],
- controller: controller,
- isIncrease: false,
- iconTheme: iconTheme,
- afterButtonPressed: afterButtonPressed,
- ),
- if (showDividers && isButtonGroupShown[4] && isButtonGroupShown[5])
- QuillDivider(axis,
- color: sectionDividerColor, space: sectionDividerSpace),
- if (showLink)
- LinkStyleButton(
- tooltip: buttonTooltips[ToolbarButtons.link],
- controller: controller,
- iconSize: toolbarIconSize,
- iconTheme: iconTheme,
- dialogTheme: dialogTheme,
- afterButtonPressed: afterButtonPressed,
- linkRegExp: linkRegExp,
- linkDialogAction: linkDialogAction,
- ),
- if (showSearchButton)
- SearchButton(
- icon: Icons.search,
- iconSize: toolbarIconSize,
- tooltip: buttonTooltips[ToolbarButtons.search],
- controller: controller,
- iconTheme: iconTheme,
- dialogTheme: dialogTheme,
- afterButtonPressed: afterButtonPressed,
- ),
- if (customButtons.isNotEmpty)
- if (showDividers)
+ childrenBuilder: (context) {
+ final controller = context.requireQuillController;
+
+ return [
+ if (showUndo)
+ HistoryButton(
+ icon: Icons.undo_outlined,
+ iconSize: toolbarIconSize,
+ tooltip: buttonTooltips[ToolbarButtons.undo],
+ controller: controller,
+ undo: true,
+ iconTheme: iconTheme,
+ afterButtonPressed: afterButtonPressed,
+ ),
+ if (showRedo)
+ HistoryButton(
+ icon: Icons.redo_outlined,
+ iconSize: toolbarIconSize,
+ tooltip: buttonTooltips[ToolbarButtons.redo],
+ controller: controller,
+ undo: false,
+ iconTheme: iconTheme,
+ afterButtonPressed: afterButtonPressed,
+ ),
+ if (showFontFamily)
+ QuillFontFamilyButton(
+ iconTheme: iconTheme,
+ iconSize: toolbarIconSize,
+ tooltip: buttonTooltips[ToolbarButtons.fontFamily],
+ attribute: Attribute.font,
+ controller: controller,
+ rawItemsMap: fontFamilies,
+ afterButtonPressed: afterButtonPressed,
+ ),
+ if (showFontSize)
+ QuillFontSizeButton(
+ iconTheme: iconTheme,
+ iconSize: toolbarIconSize,
+ tooltip: buttonTooltips[ToolbarButtons.fontSize],
+ attribute: Attribute.size,
+ controller: controller,
+ rawItemsMap: fontSizes,
+ afterButtonPressed: afterButtonPressed,
+ ),
+ if (showBoldButton)
+ ToggleStyleButton(
+ attribute: Attribute.bold,
+ icon: Icons.format_bold,
+ iconSize: toolbarIconSize,
+ tooltip: buttonTooltips[ToolbarButtons.bold],
+ controller: controller,
+ iconTheme: iconTheme,
+ afterButtonPressed: afterButtonPressed,
+ ),
+ if (showSubscript)
+ ToggleStyleButton(
+ attribute: Attribute.subscript,
+ icon: Icons.subscript,
+ iconSize: toolbarIconSize,
+ tooltip: buttonTooltips[ToolbarButtons.subscript],
+ controller: controller,
+ iconTheme: iconTheme,
+ afterButtonPressed: afterButtonPressed,
+ ),
+ if (showSuperscript)
+ ToggleStyleButton(
+ attribute: Attribute.superscript,
+ icon: Icons.superscript,
+ iconSize: toolbarIconSize,
+ tooltip: buttonTooltips[ToolbarButtons.superscript],
+ controller: controller,
+ iconTheme: iconTheme,
+ afterButtonPressed: afterButtonPressed,
+ ),
+ if (showItalicButton)
+ ToggleStyleButton(
+ attribute: Attribute.italic,
+ icon: Icons.format_italic,
+ iconSize: toolbarIconSize,
+ tooltip: buttonTooltips[ToolbarButtons.italic],
+ controller: controller,
+ iconTheme: iconTheme,
+ afterButtonPressed: afterButtonPressed,
+ ),
+ if (showSmallButton)
+ ToggleStyleButton(
+ attribute: Attribute.small,
+ icon: Icons.format_size,
+ iconSize: toolbarIconSize,
+ tooltip: buttonTooltips[ToolbarButtons.small],
+ controller: controller,
+ iconTheme: iconTheme,
+ afterButtonPressed: afterButtonPressed,
+ ),
+ if (showUnderLineButton)
+ ToggleStyleButton(
+ attribute: Attribute.underline,
+ icon: Icons.format_underline,
+ iconSize: toolbarIconSize,
+ tooltip: buttonTooltips[ToolbarButtons.underline],
+ controller: controller,
+ iconTheme: iconTheme,
+ afterButtonPressed: afterButtonPressed,
+ ),
+ if (showStrikeThrough)
+ ToggleStyleButton(
+ attribute: Attribute.strikeThrough,
+ icon: Icons.format_strikethrough,
+ iconSize: toolbarIconSize,
+ tooltip: buttonTooltips[ToolbarButtons.strikeThrough],
+ controller: controller,
+ iconTheme: iconTheme,
+ afterButtonPressed: afterButtonPressed,
+ ),
+ if (showInlineCode)
+ ToggleStyleButton(
+ attribute: Attribute.inlineCode,
+ icon: Icons.code,
+ iconSize: toolbarIconSize,
+ tooltip: buttonTooltips[ToolbarButtons.inlineCode],
+ controller: controller,
+ iconTheme: iconTheme,
+ afterButtonPressed: afterButtonPressed,
+ ),
+ if (showColorButton)
+ ColorButton(
+ icon: Icons.color_lens,
+ iconSize: toolbarIconSize,
+ tooltip: buttonTooltips[ToolbarButtons.color],
+ controller: controller,
+ background: false,
+ iconTheme: iconTheme,
+ afterButtonPressed: afterButtonPressed,
+ dialogBarrierColor:
+ context.requireSharedQuillConfigurations.dialogBarrierColor,
+ ),
+ if (showBackgroundColorButton)
+ ColorButton(
+ icon: Icons.format_color_fill,
+ iconSize: toolbarIconSize,
+ tooltip: buttonTooltips[ToolbarButtons.backgroundColor],
+ controller: controller,
+ background: true,
+ iconTheme: iconTheme,
+ afterButtonPressed: afterButtonPressed,
+ dialogBarrierColor:
+ context.requireSharedQuillConfigurations.dialogBarrierColor,
+ ),
+ if (showClearFormat)
+ ClearFormatButton(
+ icon: Icons.format_clear,
+ iconSize: toolbarIconSize,
+ tooltip: buttonTooltips[ToolbarButtons.clearFormat],
+ controller: controller,
+ iconTheme: iconTheme,
+ afterButtonPressed: afterButtonPressed,
+ ),
+ if (embedButtons != null)
+ for (final builder in embedButtons)
+ builder(controller, toolbarIconSize, iconTheme, dialogTheme),
+ if (showDividers &&
+ isButtonGroupShown[0] &&
+ (isButtonGroupShown[1] ||
+ isButtonGroupShown[2] ||
+ isButtonGroupShown[3] ||
+ isButtonGroupShown[4] ||
+ isButtonGroupShown[5]))
+ QuillDivider(
+ axis,
+ color: sectionDividerColor,
+ space: sectionDividerSpace,
+ ),
+ if (showAlignmentButtons)
+ SelectAlignmentButton(
+ controller: controller,
+ tooltips: Map.of(buttonTooltips)
+ ..removeWhere((key, value) => ![
+ ToolbarButtons.leftAlignment,
+ ToolbarButtons.centerAlignment,
+ ToolbarButtons.rightAlignment,
+ ToolbarButtons.justifyAlignment,
+ ].contains(key)),
+ iconSize: toolbarIconSize,
+ iconTheme: iconTheme,
+ showLeftAlignment: showLeftAlignment,
+ showCenterAlignment: showCenterAlignment,
+ showRightAlignment: showRightAlignment,
+ showJustifyAlignment: showJustifyAlignment,
+ afterButtonPressed: afterButtonPressed,
+ ),
+ if (showDirection)
+ ToggleStyleButton(
+ attribute: Attribute.rtl,
+ tooltip: buttonTooltips[ToolbarButtons.direction],
+ controller: controller,
+ icon: Icons.format_textdirection_r_to_l,
+ iconSize: toolbarIconSize,
+ iconTheme: iconTheme,
+ afterButtonPressed: afterButtonPressed,
+ ),
+ if (showDividers &&
+ isButtonGroupShown[1] &&
+ (isButtonGroupShown[2] ||
+ isButtonGroupShown[3] ||
+ isButtonGroupShown[4] ||
+ isButtonGroupShown[5]))
QuillDivider(
axis,
color: sectionDividerColor,
space: sectionDividerSpace,
),
- for (final customButton in customButtons)
- if (customButton.child != null) ...[
- InkWell(
- onTap: customButton.onTap,
- child: customButton.child,
+ if (showHeaderStyle)
+ SelectHeaderStyleButton(
+ tooltip: buttonTooltips[ToolbarButtons.headerStyle],
+ controller: controller,
+ axis: axis,
+ iconSize: toolbarIconSize,
+ iconTheme: iconTheme,
+ afterButtonPressed: afterButtonPressed,
+ ),
+ if (showDividers &&
+ showHeaderStyle &&
+ isButtonGroupShown[2] &&
+ (isButtonGroupShown[3] ||
+ isButtonGroupShown[4] ||
+ isButtonGroupShown[5]))
+ QuillDivider(
+ axis,
+ color: sectionDividerColor,
+ space: sectionDividerSpace,
),
- ] else ...[
- CustomButton(
- onPressed: customButton.onTap,
- icon: customButton.icon,
- iconColor: customButton.iconColor,
+ if (showListNumbers)
+ ToggleStyleButton(
+ attribute: Attribute.ol,
+ tooltip: buttonTooltips[ToolbarButtons.listNumbers],
+ controller: controller,
+ icon: Icons.format_list_numbered,
iconSize: toolbarIconSize,
iconTheme: iconTheme,
afterButtonPressed: afterButtonPressed,
- tooltip: customButton.tooltip,
),
- ],
- ],
+ if (showListBullets)
+ ToggleStyleButton(
+ attribute: Attribute.ul,
+ tooltip: buttonTooltips[ToolbarButtons.listBullets],
+ controller: controller,
+ icon: Icons.format_list_bulleted,
+ iconSize: toolbarIconSize,
+ iconTheme: iconTheme,
+ afterButtonPressed: afterButtonPressed,
+ ),
+ if (showListCheck)
+ ToggleCheckListButton(
+ attribute: Attribute.unchecked,
+ tooltip: buttonTooltips[ToolbarButtons.listChecks],
+ controller: controller,
+ icon: Icons.check_box,
+ iconSize: toolbarIconSize,
+ iconTheme: iconTheme,
+ afterButtonPressed: afterButtonPressed,
+ ),
+ if (showCodeBlock)
+ ToggleStyleButton(
+ attribute: Attribute.codeBlock,
+ tooltip: buttonTooltips[ToolbarButtons.codeBlock],
+ controller: controller,
+ icon: Icons.code,
+ iconSize: toolbarIconSize,
+ iconTheme: iconTheme,
+ afterButtonPressed: afterButtonPressed,
+ ),
+ if (showDividers &&
+ isButtonGroupShown[3] &&
+ (isButtonGroupShown[4] || isButtonGroupShown[5]))
+ QuillDivider(axis,
+ color: sectionDividerColor, space: sectionDividerSpace),
+ if (showQuote)
+ ToggleStyleButton(
+ attribute: Attribute.blockQuote,
+ tooltip: buttonTooltips[ToolbarButtons.quote],
+ controller: controller,
+ icon: Icons.format_quote,
+ iconSize: toolbarIconSize,
+ iconTheme: iconTheme,
+ afterButtonPressed: afterButtonPressed,
+ ),
+ if (showIndent)
+ IndentButton(
+ icon: Icons.format_indent_increase,
+ iconSize: toolbarIconSize,
+ tooltip: buttonTooltips[ToolbarButtons.indentIncrease],
+ controller: controller,
+ isIncrease: true,
+ iconTheme: iconTheme,
+ afterButtonPressed: afterButtonPressed,
+ ),
+ if (showIndent)
+ IndentButton(
+ icon: Icons.format_indent_decrease,
+ iconSize: toolbarIconSize,
+ tooltip: buttonTooltips[ToolbarButtons.indentDecrease],
+ controller: controller,
+ isIncrease: false,
+ iconTheme: iconTheme,
+ afterButtonPressed: afterButtonPressed,
+ ),
+ if (showDividers && isButtonGroupShown[4] && isButtonGroupShown[5])
+ QuillDivider(axis,
+ color: sectionDividerColor, space: sectionDividerSpace),
+ if (showLink)
+ LinkStyleButton(
+ tooltip: buttonTooltips[ToolbarButtons.link],
+ controller: controller,
+ iconSize: toolbarIconSize,
+ iconTheme: iconTheme,
+ dialogTheme: dialogTheme,
+ afterButtonPressed: afterButtonPressed,
+ linkRegExp: linkRegExp,
+ linkDialogAction: linkDialogAction,
+ dialogBarrierColor:
+ context.requireSharedQuillConfigurations.dialogBarrierColor,
+ ),
+ if (showSearchButton)
+ SearchButton(
+ icon: Icons.search,
+ iconSize: toolbarIconSize,
+ dialogBarrierColor:
+ context.requireSharedQuillConfigurations.dialogBarrierColor,
+ tooltip: buttonTooltips[ToolbarButtons.search],
+ controller: controller,
+ iconTheme: iconTheme,
+ dialogTheme: dialogTheme,
+ afterButtonPressed: afterButtonPressed,
+ ),
+ if (customButtons.isNotEmpty)
+ if (showDividers)
+ QuillDivider(
+ axis,
+ color: sectionDividerColor,
+ space: sectionDividerSpace,
+ ),
+ for (final customButton in customButtons)
+ if (customButton.child != null) ...[
+ InkWell(
+ onTap: customButton.onTap,
+ child: customButton.child,
+ ),
+ ] else ...[
+ CustomButton(
+ onPressed: customButton.onTap,
+ icon: customButton.icon,
+ iconColor: customButton.iconColor,
+ iconSize: toolbarIconSize,
+ iconTheme: iconTheme,
+ afterButtonPressed: afterButtonPressed,
+ tooltip: customButton.tooltip,
+ ),
+ ],
+ ];
+ },
);
}
- final List children;
+ final QuillToolbarChildrenBuilder childrenBuilder;
final Axis axis;
final double toolbarSize;
final double toolbarSectionSpacing;
@@ -620,10 +625,6 @@ class QuillToolbar extends StatelessWidget implements PreferredSizeWidget {
/// is given.
final Color? color;
- // We will add this in the next major release and not now
- /// The barrier color of the shown dialogs
- // final Color dialogbarrierColor;
-
/// The locale to use for the editor toolbar, defaults to system locale
/// More https://github.com/singerdmx/flutter-quill#translation
final Locale? locale;
@@ -659,7 +660,7 @@ class QuillToolbar extends StatelessWidget implements PreferredSizeWidget {
crossAxisAlignment: toolbarIconCrossAlignment,
runSpacing: 4,
spacing: toolbarSectionSpacing,
- children: children,
+ children: childrenBuilder(context),
)
: Container(
decoration: decoration ??
@@ -672,7 +673,7 @@ class QuillToolbar extends StatelessWidget implements PreferredSizeWidget {
),
child: ArrowIndicatedButtonList(
axis: axis,
- buttons: children,
+ buttons: childrenBuilder(context),
),
),
);
diff --git a/lib/src/widgets/toolbar/link_style_button2.dart b/lib/src/widgets/toolbar/link_style_button2.dart
index 9e3de80e..3655534d 100644
--- a/lib/src/widgets/toolbar/link_style_button2.dart
+++ b/lib/src/widgets/toolbar/link_style_button2.dart
@@ -2,7 +2,8 @@ import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:url_launcher/link.dart';
-import '../../../extensions.dart';
+import '../../../extensions.dart'
+ show UtilityWidgets, AutoFormatMultipleLinksRule;
import '../../../translations.dart';
import '../../models/documents/attribute.dart';
import '../../models/themes/quill_dialog_theme.dart';
diff --git a/lib/src/widgets/utils/provider.dart b/lib/src/widgets/utils/provider.dart
new file mode 100644
index 00000000..0148f2e4
--- /dev/null
+++ b/lib/src/widgets/utils/provider.dart
@@ -0,0 +1,50 @@
+import 'package:flutter/foundation.dart' show debugPrint, kDebugMode;
+import 'package:flutter/widgets.dart' show InheritedWidget, BuildContext;
+
+import '../../core/quill_configurations.dart';
+
+class QuillProvider extends InheritedWidget {
+ const QuillProvider({
+ required this.configurations,
+ required super.child,
+ });
+
+ /// Controller object which establishes a link between a rich text document
+ /// and this editor.
+ ///
+ /// Must not be null.
+ final QuillConfigurations configurations;
+
+ @override
+ bool updateShouldNotify(covariant InheritedWidget oldWidget) {
+ throw false;
+ }
+
+ static QuillProvider? of(BuildContext context) {
+ return context.dependOnInheritedWidgetOfExactType();
+ }
+
+ static QuillProvider ofNotNull(BuildContext context) {
+ final provider = of(context);
+ if (provider == null) {
+ if (kDebugMode) {
+ debugPrint(
+ 'The quill provider must be provided in the widget tree.',
+ );
+ }
+ throw ArgumentError.checkNotNull(
+ 'You are using a widget in the Flutter quill library that require '
+ 'The Quill provider widget to be in the parent widget tree '
+ 'because '
+ 'The provider is $provider. Please make sure to wrap this widget'
+ ' with'
+ ' QuillProvider widget. '
+ 'You might using QuillEditor and QuillToolbar so make sure to'
+ ' wrap them with the quill provider widget and setup the required '
+ 'configurations',
+ 'QuillProvider',
+ );
+ }
+ return provider;
+ }
+}
diff --git a/pubspec.yaml b/pubspec.yaml
index 59faa2bb..0e1921d4 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -1,8 +1,15 @@
name: flutter_quill
description: A rich text editor built for the modern Android, iOS, web and desktop platforms. It is the WYSIWYG editor and a Quill component for Flutter.
-version: 7.4.16
+version: 7.5.0
homepage: https://1o24bbs.com/c/bulletjournal/108
repository: https://github.com/singerdmx/flutter-quill
+platforms:
+ android:
+ ios:
+ linux:
+ macos:
+ web:
+ windows:
environment:
sdk: ">=2.17.0 <4.0.0"
@@ -24,40 +31,7 @@ dependencies:
platform: ^3.1.3
pasteboard: ^0.2.0
- # Dependencies for testing utilities
flutter_test:
sdk: flutter
-# For information on the generic Dart part of this file, see the
-# following page: https://dart.dev/tools/pub/pubspec
-# The following section is specific to Flutter.
-flutter: null
-# To add assets to your package, add an assets section, like this:
-# assets:
-# - images/a_dot_burr.jpeg
-# - images/a_dot_ham.jpeg
-#
-# For details regarding assets in packages, see
-# https://flutter.dev/assets-and-images/#from-packages
-#
-# An image asset can refer to one or more resolution-specific "variants", see
-# https://flutter.dev/assets-and-images/#resolution-aware.
-# To add custom fonts to your package, add a fonts section here,
-# in this "flutter" section. Each entry in this list should have a
-# "family" key with the font family name, and a "fonts" key with a
-# list giving the asset and other descriptors for the font. For
-# example:
-# fonts:
-# - family: Schyler
-# fonts:
-# - asset: fonts/Schyler-Regular.ttf
-# - asset: fonts/Schyler-Italic.ttf
-# style: italic
-# - family: Trajan Pro
-# fonts:
-# - asset: fonts/TrajanPro.ttf
-# - asset: fonts/TrajanPro_Bold.ttf
-# weight: 700
-#
-# For details regarding fonts in packages, see
-# https://flutter.dev/custom-fonts/#from-packages
+flutter: null
\ No newline at end of file
diff --git a/test/bug_fix_test.dart b/test/bug_fix_test.dart
index 0689476e..ee53926c 100644
--- a/test/bug_fix_test.dart
+++ b/test/bug_fix_test.dart
@@ -12,17 +12,27 @@ void main() {
(tester) async {
const tooltip = 'custom button';
- await tester.pumpWidget(MaterialApp(
- home: QuillToolbar.basic(
- showRedo: false,
- controller: QuillController.basic(),
- customButtons: [const QuillCustomButton(tooltip: tooltip)],
- )));
+ await tester.pumpWidget(
+ MaterialApp(
+ home: QuillProvider(
+ configurations: QuillConfigurations(
+ controller: QuillController.basic(),
+ ),
+ child: QuillToolbar.basic(
+ showRedo: false,
+ customButtons: [
+ const QuillCustomButton(tooltip: tooltip),
+ ],
+ ),
+ ),
+ ),
+ );
final builtinFinder = find.descendant(
- of: find.byType(HistoryButton),
- matching: find.byType(QuillIconButton),
- matchRoot: true);
+ of: find.byType(HistoryButton),
+ matching: find.byType(QuillIconButton),
+ matchRoot: true,
+ );
expect(builtinFinder, findsOneWidget);
final builtinButton =
builtinFinder.evaluate().first.widget as QuillIconButton;
@@ -46,7 +56,9 @@ void main() {
setUp(() {
controller = QuillController.basic();
- editor = QuillEditor.basic(controller: controller, readOnly: false);
+ editor = QuillEditor.basic(
+ readOnly: false,
+ );
});
tearDown(() {
@@ -55,7 +67,16 @@ void main() {
testWidgets('Refocus editor after controller clears document',
(tester) async {
- await tester.pumpWidget(MaterialApp(home: Column(children: [editor])));
+ await tester.pumpWidget(
+ QuillProvider(
+ configurations: QuillConfigurations(controller: controller),
+ child: MaterialApp(
+ home: Column(
+ children: [editor],
+ ),
+ ),
+ ),
+ );
await tester.quillEnterText(find.byType(QuillEditor), 'test\n');
editor.focusNode.unfocus();
@@ -68,7 +89,14 @@ void main() {
testWidgets('Refocus editor after removing block attribute',
(tester) async {
- await tester.pumpWidget(MaterialApp(home: Column(children: [editor])));
+ await tester.pumpWidget(QuillProvider(
+ configurations: QuillConfigurations(controller: controller),
+ child: MaterialApp(
+ home: Column(
+ children: [editor],
+ ),
+ ),
+ ));
await tester.quillEnterText(find.byType(QuillEditor), 'test\n');
controller.formatSelection(Attribute.ul);
@@ -81,7 +109,16 @@ void main() {
});
testWidgets('Tap checkbox in unfocused editor', (tester) async {
- await tester.pumpWidget(MaterialApp(home: Column(children: [editor])));
+ await tester.pumpWidget(
+ QuillProvider(
+ configurations: QuillConfigurations(controller: controller),
+ child: MaterialApp(
+ home: Column(
+ children: [editor],
+ ),
+ ),
+ ),
+ );
await tester.quillEnterText(find.byType(QuillEditor), 'test\n');
controller.formatSelection(Attribute.unchecked);
diff --git a/test/widgets/editor_test.dart b/test/widgets/editor_test.dart
index dccf85ea..d3453ed6 100644
--- a/test/widgets/editor_test.dart
+++ b/test/widgets/editor_test.dart
@@ -4,7 +4,7 @@ import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_quill/flutter_quill.dart';
import 'package:flutter_quill/flutter_quill_test.dart';
-import 'package:flutter_quill/src/widgets/raw_editor.dart';
+import 'package:flutter_quill/src/widgets/raw_editor/raw_editor.dart';
import 'package:flutter_test/flutter_test.dart';
void main() {
@@ -22,8 +22,11 @@ void main() {
group('QuillEditor', () {
testWidgets('Keyboard entered text is stored in document', (tester) async {
await tester.pumpWidget(
- MaterialApp(
- home: QuillEditor.basic(controller: controller, readOnly: false),
+ QuillProvider(
+ configurations: QuillConfigurations(controller: controller),
+ child: MaterialApp(
+ home: QuillEditor.basic(readOnly: false),
+ ),
),
);
await tester.quillEnterText(find.byType(QuillEditor), 'test\n');
@@ -35,20 +38,22 @@ void main() {
String? latestUri;
await tester.pumpWidget(
MaterialApp(
- home: QuillEditor(
- controller: controller,
- focusNode: FocusNode(),
- scrollController: ScrollController(),
- scrollable: true,
- padding: const EdgeInsets.all(0),
- autoFocus: true,
- readOnly: false,
- expands: true,
- contentInsertionConfiguration: ContentInsertionConfiguration(
- onContentInserted: (content) {
- latestUri = content.uri;
- },
- allowedMimeTypes: const ['image/gif'],
+ home: QuillProvider(
+ configurations: QuillConfigurations(controller: controller),
+ child: QuillEditor(
+ focusNode: FocusNode(),
+ scrollController: ScrollController(),
+ scrollable: true,
+ padding: const EdgeInsets.all(0),
+ autoFocus: true,
+ readOnly: false,
+ expands: true,
+ contentInsertionConfiguration: ContentInsertionConfiguration(
+ onContentInserted: (content) {
+ latestUri = content.uri;
+ },
+ allowedMimeTypes: const ['image/gif'],
+ ),
),
),
),
@@ -105,19 +110,23 @@ void main() {
}
testWidgets('custom context menu builder', (tester) async {
- await tester.pumpWidget(MaterialApp(
- home: QuillEditor(
- controller: controller,
- focusNode: FocusNode(),
- scrollController: ScrollController(),
- scrollable: true,
- padding: EdgeInsets.zero,
- autoFocus: true,
- readOnly: false,
- expands: true,
- contextMenuBuilder: customBuilder,
+ await tester.pumpWidget(
+ MaterialApp(
+ home: QuillProvider(
+ configurations: QuillConfigurations(controller: controller),
+ child: QuillEditor(
+ focusNode: FocusNode(),
+ scrollController: ScrollController(),
+ scrollable: true,
+ padding: EdgeInsets.zero,
+ autoFocus: true,
+ readOnly: false,
+ expands: true,
+ contextMenuBuilder: customBuilder,
+ ),
+ ),
),
- ));
+ );
// Long press to show menu
await tester.longPress(find.byType(QuillEditor));