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/pages/home_page.dart b/example/lib/pages/home_page.dart index 851491bb..05fa8dfc 100644 --- a/example/lib/pages/home_page.dart +++ b/example/lib/pages/home_page.dart @@ -249,7 +249,7 @@ class _HomePageState extends State { ]); } var toolbar = QuillToolbar.basic( - controller: _controller!, + context: context, embedButtons: FlutterQuillEmbeds.buttons( // provide a callback to enable picking images from device. // if omit, "image" button only allows adding images from url. @@ -266,7 +266,7 @@ class _HomePageState extends State { ); if (kIsWeb) { toolbar = QuillToolbar.basic( - controller: _controller!, + context: context, embedButtons: FlutterQuillEmbeds.buttons( onImagePickCallback: _onImagePickCallback, webImagePickImpl: _webImagePickImpl, @@ -277,7 +277,7 @@ class _HomePageState extends State { } if (_isDesktop()) { toolbar = QuillToolbar.basic( - controller: _controller!, + context: context, embedButtons: FlutterQuillEmbeds.buttons( onImagePickCallback: _onImagePickCallback, filePickImpl: openFileSystemPickerForDesktop, @@ -288,26 +288,35 @@ class _HomePageState extends State { } 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( + controller: _controller ?? + (throw ArgumentError.checkNotNull( + _controller, + 'Quill 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: toolbar, + )) + : Container(child: toolbar) + ], + ), ), ); } diff --git a/example/lib/pages/read_only_page.dart b/example/lib/pages/read_only_page.dart index d0ae032e..0909b00c 100644 --- a/example/lib/pages/read_only_page.dart +++ b/example/lib/pages/read_only_page.dart @@ -26,9 +26,10 @@ 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), + ), ); } diff --git a/example/lib/widgets/demo_scaffold.dart b/example/lib/widgets/demo_scaffold.dart index 93d38663..a35c9723 100644 --- a/example/lib/widgets/demo_scaffold.dart +++ b/example/lib/widgets/demo_scaffold.dart @@ -91,14 +91,15 @@ class _DemoScaffoldState extends State { } final actions = widget.actions ?? []; var toolbar = QuillToolbar.basic( - controller: _controller!, + context: context, embedButtons: FlutterQuillEmbeds.buttons(), ); if (_isDesktop()) { toolbar = QuillToolbar.basic( - controller: _controller!, + context: context, embedButtons: FlutterQuillEmbeds.buttons( - filePickImpl: openFileSystemPickerForDesktop), + filePickImpl: openFileSystemPickerForDesktop, + ), ); } return Scaffold( 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..7334b868 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -23,14 +23,14 @@ 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: diff --git a/flutter_quill_extensions/pubspec.yaml b/flutter_quill_extensions/pubspec.yaml index 7ec60cf0..52941035 100644 --- a/flutter_quill_extensions/pubspec.yaml +++ b/flutter_quill_extensions/pubspec.yaml @@ -12,10 +12,10 @@ 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 + flutter_quill: + path: /Users/ahmedhnewa/development/playground/framework_based/flutter/flutter-quill http: ^1.1.0 image_picker: ">=1.0.4" diff --git a/lib/flutter_quill.dart b/lib/flutter_quill.dart index 22a0a20f..08a50620 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/quill_provider.dart'; diff --git a/lib/src/core/quill_configurations.dart b/lib/src/core/quill_configurations.dart new file mode 100644 index 00000000..addbeb70 --- /dev/null +++ b/lib/src/core/quill_configurations.dart @@ -0,0 +1,12 @@ +import 'package:flutter/foundation.dart' show immutable; + +import '../../flutter_quill.dart'; + +@immutable +class QuillConfigurations { + const QuillConfigurations({ + required this.controller, + }); + + final QuillController controller; +} diff --git a/lib/src/utils/extensions/build_context.dart b/lib/src/utils/extensions/build_context.dart new file mode 100644 index 00000000..6f325c24 --- /dev/null +++ b/lib/src/utils/extensions/build_context.dart @@ -0,0 +1,21 @@ +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; + } +} diff --git a/lib/src/widgets/toolbar.dart b/lib/src/widgets/toolbar.dart index 2ea62fe6..a68a67d5 100644 --- a/lib/src/widgets/toolbar.dart +++ b/lib/src/widgets/toolbar.dart @@ -1,12 +1,14 @@ import 'package:flutter/material.dart'; import 'package:i18n_extension/i18n_widget.dart'; +import '../../flutter_quill.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 '../translations/toolbar.i18n.dart'; +import '../utils/extensions/build_context.dart'; import 'controller.dart'; import 'embeds.dart'; import 'toolbar/arrow_indicated_button_list.dart'; @@ -71,7 +73,7 @@ class QuillToolbar extends StatelessWidget implements PreferredSizeWidget { }) : super(key: key); factory QuillToolbar.basic({ - required QuillController controller, + required BuildContext context, Axis axis = Axis.horizontal, double toolbarIconSize = kDefaultIconSize, double toolbarSectionSpacing = kToolbarSectionSpacing, @@ -248,6 +250,8 @@ class QuillToolbar extends StatelessWidget implements PreferredSizeWidget { ToolbarButtons.search: 'Search'.i18n, }; + final controller = context.requireQuillController; + return QuillToolbar( key: key, axis: axis, diff --git a/lib/src/widgets/utils/quill_provider.dart b/lib/src/widgets/utils/quill_provider.dart new file mode 100644 index 00000000..ac116ce5 --- /dev/null +++ b/lib/src/widgets/utils/quill_provider.dart @@ -0,0 +1,35 @@ +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, + }); + + 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(provider, 'QuillProvider'); + } + return provider; + } +} diff --git a/test/bug_fix_test.dart b/test/bug_fix_test.dart index 0689476e..295a87f1 100644 --- a/test/bug_fix_test.dart +++ b/test/bug_fix_test.dart @@ -12,12 +12,24 @@ 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: Builder( + builder: (context) { + return QuillToolbar.basic( + context: context, + showRedo: false, + customButtons: [const QuillCustomButton(tooltip: tooltip)], + ); + }, + ), + ), + ), + ); final builtinFinder = find.descendant( of: find.byType(HistoryButton),