pull/1508/head
Ellet 1 year ago
parent bd338c00c2
commit 8e0441e224
No known key found for this signature in database
GPG Key ID: C488CC70BBCEF0D1
  1. 4
      CHANGELOG.md
  2. 59
      analysis_options.yaml
  3. 57
      example/analysis_options.yaml
  4. 14
      example/android/app/build.gradle
  5. 2
      example/android/app/src/main/AndroidManifest.xml
  6. 4
      example/android/build.gradle
  7. 3
      example/android/gradle.properties
  8. 2
      example/android/gradle/wrapper/gradle-wrapper.properties
  9. 37
      example/assets/sample_data_nomedia.json
  10. 16
      example/lib/main.dart
  11. 154
      example/lib/pages/home_page.dart
  12. 2
      example/lib/pages/read_only_page.dart
  13. 4
      example/lib/widgets/demo_scaffold.dart
  14. 4
      example/lib/widgets/time_stamp_embed_widget.dart
  15. 13
      example/pubspec.yaml
  16. 2
      example/test/widget_test.dart
  17. 3
      flutter_quill_extensions/CHANGELOG.md
  18. 2
      flutter_quill_extensions/LICENSE
  19. 2
      flutter_quill_extensions/README.md
  20. 59
      flutter_quill_extensions/analysis_options.yaml
  21. 12
      flutter_quill_extensions/lib/core/exceptions.dart
  22. 19
      flutter_quill_extensions/lib/flutter_quill_extensions.dart
  23. 24
      flutter_quill_extensions/lib/logic/extensions/controller.dart
  24. 38
      flutter_quill_extensions/lib/logic/models/config/shared_configurations.dart
  25. 1
      flutter_quill_extensions/lib/logic/services/image_picker/s_image_picker.dart
  26. 1
      flutter_quill_extensions/lib/logic/services/image_saver/s_image_saver.dart
  27. 0
      flutter_quill_extensions/lib/logic/utils/quill_image_utils.dart
  28. 2
      flutter_quill_extensions/lib/presentation/embeds/embed_types/image.dart
  29. 8
      flutter_quill_extensions/pubspec.yaml
  30. 4
      flutter_quill_test/CHANGELOG.md
  31. 2
      flutter_quill_test/LICENSE
  32. 17
      flutter_quill_test/README.md
  33. 59
      flutter_quill_test/analysis_options.yaml
  34. 34
      flutter_quill_test/lib/src/test/widget_tester_extension.dart
  35. 4
      flutter_quill_test/pubspec.yaml
  36. 1
      flutter_quill_test/test/flutter_quill_test_test.dart
  37. 68
      lib/src/core/utils/logger.dart
  38. 2
      lib/src/widgets/proxy.dart
  39. 3
      lib/src/widgets/raw_editor/raw_editor.dart
  40. 6
      lib/src/widgets/style_widgets/checkbox_point.dart
  41. 26
      lib/src/widgets/text_line.dart
  42. 8
      lib/src/widgets/toolbar/base_toolbar.dart
  43. 4
      lib/src/widgets/toolbar/buttons/link_style.dart
  44. 4
      lib/src/widgets/utils/provider.dart
  45. 4
      pubspec.yaml

@ -1,3 +1,7 @@
## [8.2.4]
- Follow flutter best practices
- Auto focus bug fix
## [8.2.3] ## [8.2.3]
- Update `README.md` - Update `README.md`

@ -1,4 +1,4 @@
include: package:lints/recommended.yaml include: package:flutter_lints/flutter.yaml
analyzer: analyzer:
errors: errors:
@ -6,32 +6,31 @@ analyzer:
unsafe_html: ignore unsafe_html: ignore
linter: linter:
rules: rules:
- always_declare_return_types always_declare_return_types: true
- always_put_required_named_parameters_first always_put_required_named_parameters_first: true
- annotate_overrides annotate_overrides: true
- avoid_empty_else avoid_empty_else: true
- avoid_escaping_inner_quotes avoid_escaping_inner_quotes: true
- avoid_print avoid_print: true
- avoid_redundant_argument_values avoid_redundant_argument_values: true
- avoid_types_on_closure_parameters avoid_types_on_closure_parameters: true
- avoid_void_async avoid_void_async: true
- cascade_invocations cascade_invocations: true
- directives_ordering directives_ordering: true
- lines_longer_than_80_chars omit_local_variable_types: true
- omit_local_variable_types prefer_const_constructors: true
- prefer_const_constructors prefer_const_constructors_in_immutables: true
- prefer_const_constructors_in_immutables prefer_const_declarations: true
- prefer_const_declarations prefer_final_fields: true
- prefer_final_fields prefer_final_in_for_each: true
- prefer_final_in_for_each prefer_final_locals: true
- prefer_final_locals prefer_initializing_formals: true
- prefer_initializing_formals prefer_int_literals: true
- prefer_int_literals prefer_interpolation_to_compose_strings: true
- prefer_interpolation_to_compose_strings prefer_relative_imports: true
- prefer_relative_imports prefer_single_quotes: true
- prefer_single_quotes sort_constructors_first: true
- sort_constructors_first sort_unnamed_constructors_first: true
- sort_unnamed_constructors_first unnecessary_lambdas: true
- unnecessary_lambdas unnecessary_parenthesis: true
- unnecessary_parenthesis unnecessary_string_interpolations: true
- unnecessary_string_interpolations

@ -1,28 +1,37 @@
# This file configures the analyzer, which statically analyzes Dart code to
# check for errors, warnings, and lints.
#
# The issues identified by the analyzer are surfaced in the UI of Dart-enabled
# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be
# invoked from the command line by running `flutter analyze`.
# The following line activates a set of recommended lints for Flutter apps,
# packages, and plugins designed to encourage good coding practices.
include: package:flutter_lints/flutter.yaml include: package:flutter_lints/flutter.yaml
analyzer:
errors:
undefined_prefixed_name: ignore
unsafe_html: ignore
linter: linter:
# The lint rules applied to this project can be customized in the
# section below to disable rules from the `package:flutter_lints/flutter.yaml`
# included above or to enable additional rules. A list of all available lints
# and their documentation is published at https://dart.dev/lints.
#
# Instead of disabling a lint rule for the entire project in the
# section below, it can also be suppressed for a single line of code
# or a specific dart file by using the `// ignore: name_of_lint` and
# `// ignore_for_file: name_of_lint` syntax on the line or in the file
# producing the lint.
rules: rules:
# avoid_print: false # Uncomment to disable the `avoid_print` rule always_declare_return_types: true
# prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule always_put_required_named_parameters_first: true
annotate_overrides: true
# Additional information about this file can be found at avoid_empty_else: true
# https://dart.dev/guides/language/analysis-options avoid_escaping_inner_quotes: true
avoid_print: true
avoid_redundant_argument_values: true
avoid_types_on_closure_parameters: true
avoid_void_async: true
cascade_invocations: true
directives_ordering: true
omit_local_variable_types: true
prefer_const_constructors: true
prefer_const_constructors_in_immutables: true
prefer_const_declarations: true
prefer_final_fields: true
prefer_final_in_for_each: true
prefer_final_locals: true
prefer_initializing_formals: true
prefer_int_literals: true
prefer_interpolation_to_compose_strings: true
prefer_relative_imports: true
prefer_single_quotes: true
sort_constructors_first: true
sort_unnamed_constructors_first: true
unnecessary_lambdas: true
unnecessary_parenthesis: true
unnecessary_string_interpolations: true
library_private_types_in_public_api: false

@ -24,16 +24,16 @@ if (flutterVersionName == null) {
android { android {
namespace "com.example.example" namespace "com.example.example"
compileSdk flutter.compileSdkVersion compileSdkVersion flutter.compileSdkVersion
ndkVersion flutter.ndkVersion ndkVersion flutter.ndkVersion
compileOptions { compileOptions {
sourceCompatibility JavaVersion.VERSION_17 sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_17 targetCompatibility JavaVersion.VERSION_1_8
} }
kotlinOptions { kotlinOptions {
jvmTarget = JavaVersion.VERSION_17.toString() jvmTarget = '1.8'
} }
sourceSets { sourceSets {
@ -41,8 +41,11 @@ android {
} }
defaultConfig { defaultConfig {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId "com.example.example" applicationId "com.example.example"
minSdkVersion 24 // You can update the following values to match your application needs.
// For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration.
minSdkVersion flutter.minSdkVersion
targetSdkVersion flutter.targetSdkVersion targetSdkVersion flutter.targetSdkVersion
versionCode flutterVersionCode.toInteger() versionCode flutterVersionCode.toInteger()
versionName flutterVersionName versionName flutterVersionName
@ -50,6 +53,7 @@ android {
buildTypes { buildTypes {
release { release {
// TODO: Add your own signing config for the release build.
// Signing with the debug keys for now, so `flutter run --release` works. // Signing with the debug keys for now, so `flutter run --release` works.
signingConfig signingConfigs.debug signingConfig signingConfigs.debug
} }

@ -1,5 +1,4 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"> <manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.CAMERA" /> <uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
@ -8,7 +7,6 @@
<uses-feature android:name="android.hardware.location.gps" /> <uses-feature android:name="android.hardware.location.gps" />
<uses-feature android:name="android.hardware.camera" android:required="false" /> <uses-feature android:name="android.hardware.camera" android:required="false" />
<application <application
android:label="example" android:label="example"
android:name="${applicationName}" android:name="${applicationName}"

@ -1,12 +1,12 @@
buildscript { buildscript {
ext.kotlin_version = '1.9.20' ext.kotlin_version = '1.7.10'
repositories { repositories {
google() google()
mavenCentral() mavenCentral()
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:8.1.2' classpath 'com.android.tools.build:gradle:7.3.0'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
} }
} }

@ -1,6 +1,3 @@
org.gradle.jvmargs=-Xmx1536M org.gradle.jvmargs=-Xmx1536M
android.useAndroidX=true android.useAndroidX=true
android.enableJetifier=true android.enableJetifier=true
android.defaults.buildfeatures.buildconfig=true
android.nonTransitiveRClass=false
android.nonFinalResIds=false

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

@ -20,43 +20,6 @@
{ {
"insert": "Quill component for Flutter" "insert": "Quill component for Flutter"
}, },
{
"attributes": {
"header": 3
},
"insert": "\n"
},
{
"insert": "This "
},
{
"attributes": {
"italic": true,
"background": "transparent"
},
"insert": "library"
},
{
"insert": " supports "
},
{
"attributes": {
"bold": true,
"background": "#ebd6ff"
},
"insert": "mobile"
},
{
"insert": " platform "
},
{
"attributes": {
"underline": true,
"bold": true,
"color": "#e60000"
},
"insert": "only"
},
{ {
"attributes": { "attributes": {
"color": "rgba(0, 0, 0, 0.847)" "color": "rgba(0, 0, 0, 0.847)"

@ -5,10 +5,12 @@ import 'pages/home_page.dart';
void main() { void main() {
WidgetsFlutterBinding.ensureInitialized(); WidgetsFlutterBinding.ensureInitialized();
runApp(MyApp()); runApp(const MyApp());
} }
class MyApp extends StatelessWidget { class MyApp extends StatelessWidget {
const MyApp({super.key});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return MaterialApp( return MaterialApp(
@ -26,18 +28,16 @@ class MyApp extends StatelessWidget {
useMaterial3: true, useMaterial3: true,
brightness: Brightness.dark, brightness: Brightness.dark,
), ),
// ignore: avoid_redundant_argument_values localizationsDelegates: const [
themeMode: ThemeMode.system,
localizationsDelegates: [
GlobalMaterialLocalizations.delegate, GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate, GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate, GlobalCupertinoLocalizations.delegate,
], ],
supportedLocales: [ supportedLocales: const [
const Locale('en', 'US'), Locale('en', 'US'),
const Locale('zh', 'HK'), Locale('zh', 'HK'),
], ],
home: HomePage(), home: const HomePage(),
); );
} }
} }

@ -1,16 +1,18 @@
// ignore_for_file: avoid_redundant_argument_values // ignore_for_file: avoid_redundant_argument_values, avoid_print
import 'dart:async'; import 'dart:async';
import 'dart:convert'; import 'dart:convert';
import 'dart:io' show File; import 'dart:io' show File;
import 'dart:ui'; import 'dart:ui';
import 'package:file_picker/file_picker.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter_quill/extensions.dart'; import 'package:flutter_quill/extensions.dart';
import 'package:flutter_quill/flutter_quill.dart'; import 'package:flutter_quill/flutter_quill.dart';
import 'package:flutter_quill_extensions/flutter_quill_extensions.dart'; import 'package:flutter_quill_extensions/flutter_quill_extensions.dart';
import 'package:flutter_quill_extensions/logic/services/image_picker/image_picker.dart';
import 'package:path/path.dart' as path; import 'package:path/path.dart' as path;
import 'package:path_provider/path_provider.dart'; import 'package:path_provider/path_provider.dart';
@ -24,6 +26,8 @@ enum _SelectionType {
} }
class HomePage extends StatefulWidget { class HomePage extends StatefulWidget {
const HomePage({super.key});
@override @override
_HomePageState createState() => _HomePageState(); _HomePageState createState() => _HomePageState();
} }
@ -54,9 +58,6 @@ class _HomePageState extends State<HomePage> {
try { try {
final result = final result =
await rootBundle.loadString('assets/sample_data_testing.json'); await rootBundle.loadString('assets/sample_data_testing.json');
// final result = await rootBundle.loadString(isDesktop()
// ? 'assets/sample_data_nomedia.json'
// : 'assets/sample_data.json');
final doc = Document.fromJson(jsonDecode(result)); final doc = Document.fromJson(jsonDecode(result));
_controller = QuillController( _controller = QuillController(
document: doc, document: doc,
@ -89,12 +90,32 @@ class _HomePageState extends State<HomePage> {
), ),
actions: [ actions: [
IconButton( IconButton(
onPressed: () { tooltip: 'Print to log',
setState(() => _isReadOnly = !_isReadOnly); onPressed: () {
}, print(
icon: Icon( jsonEncode(_controller.document.toDelta().toJson()),
_isReadOnly ? Icons.lock : Icons.edit, );
)), ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text(
'The quill delta json has been printed to the log.',
),
),
);
},
icon: const Icon(
Icons.print,
),
),
IconButton(
tooltip: 'Toggle read only',
onPressed: () {
setState(() => _isReadOnly = !_isReadOnly);
},
icon: Icon(
_isReadOnly ? Icons.lock : Icons.edit,
),
),
IconButton( IconButton(
onPressed: () => _insertTimeStamp( onPressed: () => _insertTimeStamp(
_controller, _controller,
@ -121,7 +142,116 @@ class _HomePageState extends State<HomePage> {
], ],
), ),
drawer: Drawer( drawer: Drawer(
child: _buildMenuBar(context), child: ListView(
children: [
DrawerHeader(
child: IconButton(
tooltip: 'Open document by json delta',
onPressed: () async {
final scaffoldMessenger = ScaffoldMessenger.of(context);
try {
final result = await FilePicker.platform.pickFiles(
dialogTitle: 'Pick json delta',
type: FileType.custom,
allowedExtensions: ['json'],
allowMultiple: false,
);
final file = result?.files.firstOrNull;
final filePath = file?.path;
if (file == null || filePath == null) {
return;
}
final jsonString = await XFile(filePath).readAsString();
_controller.document =
Document.fromJson(jsonDecode(jsonString));
} catch (e) {
print(
'Error while loading json delta file: ${e.toString()}',
);
scaffoldMessenger.showSnackBar(
SnackBar(
content: Text(
'Error while loading json delta file: ${e.toString()}',
),
),
);
}
},
icon: const Icon(Icons.file_copy),
),
),
ListTile(
title: const Text('Load sample data'),
onTap: () async {
final scaffoldMessenger = ScaffoldMessenger.of(context);
try {
final jsonString = await rootBundle.loadString(
'assets/sample_data.json',
);
_controller.document = Document.fromJson(
jsonDecode(jsonString),
);
} catch (e) {
print(
'Error while loading json delta file: ${e.toString()}',
);
scaffoldMessenger.showSnackBar(SnackBar(
content: Text(
'Error while loading json delta file: ${e.toString()}',
),
));
}
},
),
ListTile(
title: const Text('Load sample data with no media'),
onTap: () async {
final scaffoldMessenger = ScaffoldMessenger.of(context);
try {
final jsonString = await rootBundle.loadString(
'assets/sample_data_nomedia.json',
);
_controller.document = Document.fromJson(
jsonDecode(jsonString),
);
} catch (e) {
print(
'Error while loading json delta file: ${e.toString()}',
);
scaffoldMessenger.showSnackBar(SnackBar(
content: Text(
'Error while loading json delta file: ${e.toString()}',
),
));
}
},
),
ListTile(
title: const Text('Load testing sample data '),
onTap: () async {
final scaffoldMessenger = ScaffoldMessenger.of(context);
try {
final jsonString = await rootBundle.loadString(
'assets/sample_data_testing.json',
);
_controller.document = Document.fromJson(
jsonDecode(jsonString),
);
} catch (e) {
print(
'Error while loading json delta file: ${e.toString()}',
);
scaffoldMessenger.showSnackBar(SnackBar(
content: Text(
'Error while loading json delta file: ${e.toString()}',
),
));
}
},
),
_buildMenuBar(context),
],
),
), ),
body: _buildWelcomeEditor(context), body: _buildWelcomeEditor(context),
); );
@ -541,7 +671,7 @@ class _HomePageState extends State<HomePage> {
Navigator.push( Navigator.push(
super.context, super.context,
MaterialPageRoute( MaterialPageRoute(
builder: (context) => ReadOnlyPage(), builder: (context) => const ReadOnlyPage(),
), ),
); );
} }

@ -9,6 +9,8 @@ import 'package:flutter_quill_extensions/flutter_quill_extensions.dart';
import '../widgets/demo_scaffold.dart'; import '../widgets/demo_scaffold.dart';
class ReadOnlyPage extends StatefulWidget { class ReadOnlyPage extends StatefulWidget {
const ReadOnlyPage({super.key});
@override @override
_ReadOnlyPageState createState() => _ReadOnlyPageState(); _ReadOnlyPageState createState() => _ReadOnlyPageState();
} }

@ -18,8 +18,8 @@ class DemoScaffold extends StatefulWidget {
this.actions, this.actions,
this.showToolbar = true, this.showToolbar = true,
this.floatingActionButton, this.floatingActionButton,
Key? key, super.key,
}) : super(key: key); });
/// Filename of the document to load into the editor. /// Filename of the document to load into the editor.
final String documentFilename; final String documentFilename;

@ -21,8 +21,8 @@ class TimeStampEmbedBuilderWidget extends EmbedBuilder {
String get key => 'timeStamp'; String get key => 'timeStamp';
@override @override
String toPlainText(Embed embed) { String toPlainText(Embed node) {
return embed.value.data; return node.value.data;
} }
@override @override

@ -9,22 +9,29 @@ environment:
dependencies: dependencies:
flutter: flutter:
sdk: flutter sdk: flutter
flutter_localizations:
sdk: flutter
universal_html: ^2.2.4 universal_html: ^2.2.4
cupertino_icons: ^1.0.6 cupertino_icons: ^1.0.6
path_provider: ^2.1.1 path_provider: ^2.1.1
# filesystem_picker: ^4.0.0 # filesystem_picker: ^4.0.0
# file_picker: ^6.1.1 file_picker: ^6.1.1
flutter_quill: ^8.2.2 flutter_quill: ^8.2.3
flutter_quill_extensions: ^0.6.0-dev.5 flutter_quill_extensions: ^0.6.1
path: ^1.8.3
dependency_overrides: dependency_overrides:
flutter_quill: flutter_quill:
path: ../ path: ../
flutter_quill_extensions: flutter_quill_extensions:
path: ../flutter_quill_extensions path: ../flutter_quill_extensions
flutter_quill_test:
path: ../flutter_quill_test
dev_dependencies: dev_dependencies:
flutter_lints: ^3.0.1
flutter_quill_test: ^0.0.3
flutter_test: flutter_test:
sdk: flutter sdk: flutter

@ -12,7 +12,7 @@ import 'package:flutter_test/flutter_test.dart';
void main() { void main() {
testWidgets('Counter increments smoke test', (tester) async { testWidgets('Counter increments smoke test', (tester) async {
// Build our app and trigger a frame. // Build our app and trigger a frame.
await tester.pumpWidget(MyApp()); await tester.pumpWidget(const MyApp());
// Verify that our counter starts at 0. // Verify that our counter starts at 0.
expect(find.text('0'), findsOneWidget); expect(find.text('0'), findsOneWidget);

@ -1,3 +1,6 @@
## 0.6.2
- Add more default exports
## 0.6.1 ## 0.6.1
- Fix bug on web that causing the project to not build - Fix bug on web that causing the project to not build

@ -1,6 +1,6 @@
MIT License MIT License
Copyright (c) 2023 Xin Yao Copyright (c) 2023 Flutter Quill Team
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal

@ -57,7 +57,7 @@ dependencies:
## Usage ## Usage
Before starting using this package you must follow the setup Before starting using this package you must follow the [setup](#installation)
Set the `embedBuilders` and `embedToolbar` params in configurations of `QuillEditor` and `QuillToolbar` with the Set the `embedBuilders` and `embedToolbar` params in configurations of `QuillEditor` and `QuillToolbar` with the
values provided by this repository. values provided by this repository.

@ -1,4 +1,4 @@
include: package:lints/recommended.yaml include: package:flutter_lints/flutter.yaml
analyzer: analyzer:
errors: errors:
@ -6,32 +6,31 @@ analyzer:
unsafe_html: ignore unsafe_html: ignore
linter: linter:
rules: rules:
- always_declare_return_types always_declare_return_types: true
- always_put_required_named_parameters_first always_put_required_named_parameters_first: true
- annotate_overrides annotate_overrides: true
- avoid_empty_else avoid_empty_else: true
- avoid_escaping_inner_quotes avoid_escaping_inner_quotes: true
- avoid_print avoid_print: true
- avoid_redundant_argument_values avoid_redundant_argument_values: true
- avoid_types_on_closure_parameters avoid_types_on_closure_parameters: true
- avoid_void_async avoid_void_async: true
- cascade_invocations cascade_invocations: true
- directives_ordering directives_ordering: true
- lines_longer_than_80_chars omit_local_variable_types: true
- omit_local_variable_types prefer_const_constructors: true
- prefer_const_constructors prefer_const_constructors_in_immutables: true
- prefer_const_constructors_in_immutables prefer_const_declarations: true
- prefer_const_declarations prefer_final_fields: true
- prefer_final_fields prefer_final_in_for_each: true
- prefer_final_in_for_each prefer_final_locals: true
- prefer_final_locals prefer_initializing_formals: true
- prefer_initializing_formals prefer_int_literals: true
- prefer_int_literals prefer_interpolation_to_compose_strings: true
- prefer_interpolation_to_compose_strings prefer_relative_imports: true
- prefer_relative_imports prefer_single_quotes: true
- prefer_single_quotes sort_constructors_first: true
- sort_constructors_first sort_unnamed_constructors_first: true
- sort_unnamed_constructors_first unnecessary_lambdas: true
- unnecessary_lambdas unnecessary_parenthesis: true
- unnecessary_parenthesis unnecessary_string_interpolations: true
- unnecessary_string_interpolations

@ -1,12 +0,0 @@
// import 'package:meta/meta.dart';
// @immutable
// class NetworkException implements Exception {
// const NetworkException({required this.message});
// final String message;
// @override
// String toString() =>
// 'Error while loading something from the network: $message';
// }

@ -27,10 +27,15 @@ import 'presentation/models/config/toolbar/buttons/image.dart';
import 'presentation/models/config/toolbar/buttons/media_button.dart'; import 'presentation/models/config/toolbar/buttons/media_button.dart';
import 'presentation/models/config/toolbar/buttons/video.dart'; import 'presentation/models/config/toolbar/buttons/video.dart';
export '/logic/extensions/controller.dart';
export '/presentation/models/config/editor/webview.dart'; export '/presentation/models/config/editor/webview.dart';
export './logic/extensions/controller.dart'; export 'logic/models/config/shared_configurations.dart';
export 'presentation/embeds/editor/image/image.dart';
export 'presentation/embeds/editor/image/image_web.dart'; export 'presentation/embeds/editor/image/image_web.dart';
export 'presentation/embeds/editor/unknown.dart'; export 'presentation/embeds/editor/unknown.dart';
export 'presentation/embeds/editor/video/video.dart';
export 'presentation/embeds/editor/video/video_web.dart';
export 'presentation/embeds/editor/webview.dart';
export 'presentation/embeds/embed_types.dart'; export 'presentation/embeds/embed_types.dart';
export 'presentation/embeds/embed_types/image.dart'; export 'presentation/embeds/embed_types/image.dart';
export 'presentation/embeds/embed_types/video.dart'; export 'presentation/embeds/embed_types/video.dart';
@ -42,6 +47,11 @@ export 'presentation/embeds/toolbar/utils/image_video_utils.dart';
export 'presentation/embeds/toolbar/video_button/video_button.dart'; export 'presentation/embeds/toolbar/video_button/video_button.dart';
export 'presentation/embeds/utils.dart'; export 'presentation/embeds/utils.dart';
export 'presentation/models/config/editor/image/image.dart'; export 'presentation/models/config/editor/image/image.dart';
// TODO: Temporary
// ignore: unused_import
export 'presentation/models/config/editor/image/image_web.dart';
export 'presentation/models/config/editor/video/video.dart';
export 'presentation/models/config/editor/video/video_web.dart';
export 'presentation/models/config/toolbar/buttons/camera.dart'; export 'presentation/models/config/toolbar/buttons/camera.dart';
export 'presentation/models/config/toolbar/buttons/formula.dart'; export 'presentation/models/config/toolbar/buttons/formula.dart';
export 'presentation/models/config/toolbar/buttons/image.dart'; export 'presentation/models/config/toolbar/buttons/image.dart';
@ -111,9 +121,12 @@ class FlutterQuillEmbeds {
/// Returns a list of embed builders specifically designed for web support. /// Returns a list of embed builders specifically designed for web support.
/// ///
/// [QuillEditorImageEmbedBuilderWeb] is the embed builder for handling /// [QuillEditorWebImageEmbedBuilder] is the embed builder for handling
/// images on the web. /// images on the web.
/// ///
/// [QuillEditorWebVideoEmbedBuilder] is the embed builder for handling
/// videos iframe on the web.
///
static List<EmbedBuilder> editorsWebBuilders( static List<EmbedBuilder> editorsWebBuilders(
{QuillEditorWebImageEmbedConfigurations? imageEmbedConfigurations = {QuillEditorWebImageEmbedConfigurations? imageEmbedConfigurations =
const QuillEditorWebImageEmbedConfigurations(), const QuillEditorWebImageEmbedConfigurations(),
@ -122,7 +135,7 @@ class FlutterQuillEmbeds {
if (!kIsWeb) { if (!kIsWeb) {
throw UnsupportedError( throw UnsupportedError(
'The editorsWebBuilders() is only for web, please use editorBuilders() ' 'The editorsWebBuilders() is only for web, please use editorBuilders() '
'instead', 'instead for other platforms',
); );
} }
return [ return [

@ -2,9 +2,16 @@ import 'package:flutter_quill/flutter_quill.dart';
import '../../presentation/embeds/editor/webview.dart'; import '../../presentation/embeds/editor/webview.dart';
/// Extension functions on [QuillController]
/// that make it easier to insert the embed blocks
///
/// and provide some other extra utilities
extension QuillControllerExt on QuillController { extension QuillControllerExt on QuillController {
int get index => selection.baseOffset; int get index => selection.baseOffset;
int get length => selection.extentOffset - index; int get length => selection.extentOffset - index;
/// Insert webview embed block, it requires [initialUrl] to load
/// the initial page
void insertWebViewBlock({ void insertWebViewBlock({
required String initialUrl, required String initialUrl,
}) { }) {
@ -24,19 +31,32 @@ extension QuillControllerExt on QuillController {
); );
} }
/// Insert image embed block, it requires the [imageSource]
///
/// it could be local image on the system file
/// http image on the network
///
/// image base 64
void insertImageBlock({ void insertImageBlock({
required String imageUrl, required String imageSource,
}) { }) {
this this
..skipRequestKeyboard = true ..skipRequestKeyboard = true
..replaceText( ..replaceText(
index, index,
length, length,
BlockEmbed.image(imageUrl), BlockEmbed.image(imageSource),
null, null,
); );
} }
/// Insert video embed block, it requires the [videoUrl]
///
/// it could be the video url directly (.mp4)
/// either locally on file system
/// or http video on the network
///
/// it also supports youtube video url
void insertVideoBlock({ void insertVideoBlock({
required String videoUrl, required String videoUrl,
}) { }) {

@ -5,6 +5,33 @@ import 'package:meta/meta.dart' show immutable;
import '../../services/image_picker/s_image_picker.dart'; import '../../services/image_picker/s_image_picker.dart';
import '../../services/image_saver/s_image_saver.dart'; import '../../services/image_saver/s_image_saver.dart';
/// Configurations for Flutter Quill Extensions
/// that is shared between the toolbar and editor for the extensions package
///
/// Example on how to setup it:
///
/// ```dart
/// QuillProvider(
/// configurations: QuillConfigurations(
/// sharedConfigurations: const QuillSharedConfigurations(
/// extraConfigurations: {
/// QuillSharedExtensionsConfigurations.key:
/// QuillSharedExtensionsConfigurations(
/// // Feel free to explore it
/// ),
/// },
/// ),
/// controller: _controller,
/// ),
/// child: const Column(
/// children: [
/// // QuillToolbar
/// // QuillEditor
/// // ...
/// ],
// ),
/// )
/// ```
@immutable @immutable
class QuillSharedExtensionsConfigurations { class QuillSharedExtensionsConfigurations {
const QuillSharedExtensionsConfigurations({ const QuillSharedExtensionsConfigurations({
@ -33,11 +60,18 @@ class QuillSharedExtensionsConfigurations {
return const QuillSharedExtensionsConfigurations(); return const QuillSharedExtensionsConfigurations();
} }
/// The key to be used in the `extraConfigurations` property
/// which can be found in the [QuillSharedConfigurations]
/// which lives in the [QuillConfigurations]
///
/// which exists in the [QuillProvider]
static const String key = 'quillSharedExtensionsConfigurations'; static const String key = 'quillSharedExtensionsConfigurations';
/// Default to [ImagePickerService.defaultImpl] /// Defaults to [ImagePickerService.defaultImpl]
final ImagePickerService? _imagePickerService; final ImagePickerService? _imagePickerService;
/// A getter method which returns the [ImagePickerService] that is provided
/// by the developer, if it can't be found then we will use default impl
ImagePickerService get imagePickerService { ImagePickerService get imagePickerService {
return _imagePickerService ?? ImagePickerService.defaultImpl(); return _imagePickerService ?? ImagePickerService.defaultImpl();
} }
@ -45,6 +79,8 @@ class QuillSharedExtensionsConfigurations {
/// Default to [ImageSaverService.defaultImpl] /// Default to [ImageSaverService.defaultImpl]
final ImageSaverService? _imageSaverService; final ImageSaverService? _imageSaverService;
/// A getter method which returns the [ImageSaverService] that is provided
/// by the developer, if it can't be found then we will use default impl
ImageSaverService get imageSaverService { ImageSaverService get imageSaverService {
return _imageSaverService ?? ImageSaverService.defaultImpl(); return _imageSaverService ?? ImageSaverService.defaultImpl();
} }

@ -1,6 +1,7 @@
import 'image_picker.dart'; import 'image_picker.dart';
import 'packages/image_picker.dart'; import 'packages/image_picker.dart';
/// A service used for packing images in the extensions package
class ImagePickerService extends ImagePickerInterface { class ImagePickerService extends ImagePickerInterface {
const ImagePickerService( const ImagePickerService(
this._impl, this._impl,

@ -2,6 +2,7 @@
import 'image_saver.dart'; import 'image_saver.dart';
import 'packages/gal.dart' show ImageSaverGalImpl; import 'packages/gal.dart' show ImageSaverGalImpl;
/// A service used for saving images in the extensions package
class ImageSaverService extends ImageSaverInterface { class ImageSaverService extends ImageSaverInterface {
final ImageSaverInterface _impl; final ImageSaverInterface _impl;
const ImageSaverService(this._impl); const ImageSaverService(this._impl);

@ -30,7 +30,7 @@ OnImageInsertCallback defaultOnImageInsertCallback() {
return (imageUrl, controller) async { return (imageUrl, controller) async {
controller controller
..skipRequestKeyboard = true ..skipRequestKeyboard = true
..insertImageBlock(imageUrl: imageUrl); ..insertImageBlock(imageSource: imageUrl);
}; };
} }

@ -1,6 +1,6 @@
name: flutter_quill_extensions name: flutter_quill_extensions
description: Embed extensions for flutter_quill including image, video, formula and etc. description: Embed extensions for flutter_quill including image, video, formula and etc.
version: 0.6.1 version: 0.6.2
homepage: https://github.com/singerdmx/flutter-quill/tree/master/flutter_quill_extensions homepage: https://github.com/singerdmx/flutter-quill/tree/master/flutter_quill_extensions
repository: https://github.com/singerdmx/flutter-quill/tree/master/flutter_quill_extensions repository: https://github.com/singerdmx/flutter-quill/tree/master/flutter_quill_extensions
@ -45,9 +45,9 @@ dependencies:
# In case you are working on changes for both libraries # In case you are working on changes for both libraries
# Comment the dependency_overrides section when publishing the package, # Comment the dependency_overrides section when publishing the package,
# then uncomment it back, this will be automated later # then uncomment it back, this will be automated later
# dependency_overrides: dependency_overrides:
# flutter_quill: flutter_quill:
# path: ../ path: ../
dev_dependencies: dev_dependencies:
flutter_test: flutter_test:

@ -1,3 +1,7 @@
## 0.0.4
* Update `README.md`
* Documentation comments.
## 0.0.3 ## 0.0.3
* Update the `README.md` and description * Update the `README.md` and description

@ -1,6 +1,6 @@
MIT License MIT License
Copyright (c) Flutter Quill Team Copyright (c) 2023 Flutter Quill Team
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal

@ -2,6 +2,23 @@
Test utilities for [flutter_quill](https://pub.dev/packages/flutter_quill) which includes methods to simplify interacting with the editor in test cases. Test utilities for [flutter_quill](https://pub.dev/packages/flutter_quill) which includes methods to simplify interacting with the editor in test cases.
## Installation
Run the command in your project root folder:
```
dart pub add dev:flutter_quill_test
```
Example of how it will looks like:
```yaml
dev_dependencies:
flutter_quill_test: any # Use latest Version
flutter_lints: any
flutter_test:
sdk: flutter
```
## Testing ## Testing
To aid in testing applications using the editor an extension to the flutter `WidgetTester` is provided which includes methods to simplify interacting with the editor in test cases. To aid in testing applications using the editor an extension to the flutter `WidgetTester` is provided which includes methods to simplify interacting with the editor in test cases.

@ -1,4 +1,4 @@
include: package:lints/recommended.yaml include: package:flutter_lints/flutter.yaml
analyzer: analyzer:
errors: errors:
@ -6,32 +6,31 @@ analyzer:
unsafe_html: ignore unsafe_html: ignore
linter: linter:
rules: rules:
- always_declare_return_types always_declare_return_types: true
- always_put_required_named_parameters_first always_put_required_named_parameters_first: true
- annotate_overrides annotate_overrides: true
- avoid_empty_else avoid_empty_else: true
- avoid_escaping_inner_quotes avoid_escaping_inner_quotes: true
- avoid_print avoid_print: true
- avoid_redundant_argument_values avoid_redundant_argument_values: true
- avoid_types_on_closure_parameters avoid_types_on_closure_parameters: true
- avoid_void_async avoid_void_async: true
- cascade_invocations cascade_invocations: true
- directives_ordering directives_ordering: true
- lines_longer_than_80_chars omit_local_variable_types: true
- omit_local_variable_types prefer_const_constructors: true
- prefer_const_constructors prefer_const_constructors_in_immutables: true
- prefer_const_constructors_in_immutables prefer_const_declarations: true
- prefer_const_declarations prefer_final_fields: true
- prefer_final_fields prefer_final_in_for_each: true
- prefer_final_in_for_each prefer_final_locals: true
- prefer_final_locals prefer_initializing_formals: true
- prefer_initializing_formals prefer_int_literals: true
- prefer_int_literals prefer_interpolation_to_compose_strings: true
- prefer_interpolation_to_compose_strings prefer_relative_imports: true
- prefer_relative_imports prefer_single_quotes: true
- prefer_single_quotes sort_constructors_first: true
- sort_constructors_first sort_unnamed_constructors_first: true
- sort_unnamed_constructors_first unnecessary_lambdas: true
- unnecessary_lambdas unnecessary_parenthesis: true
- unnecessary_parenthesis unnecessary_string_interpolations: true
- unnecessary_string_interpolations

@ -2,21 +2,29 @@ import 'package:flutter/material.dart';
import 'package:flutter_quill/flutter_quill.dart'; import 'package:flutter_quill/flutter_quill.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
/// Extends /// Extensions on [WidgetTester] that have utilities that help
extension QuillEnterText on WidgetTester { /// simplify interacting with the editor in test cases.
extension QuillWidgetTesterExt on WidgetTester {
/// Give the QuillEditor widget specified by [finder] the focus. /// Give the QuillEditor widget specified by [finder] the focus.
///
Future<void> quillGiveFocus(Finder finder) { Future<void> quillGiveFocus(Finder finder) {
return TestAsyncUtils.guard(() async { return TestAsyncUtils.guard(() async {
final editor = state<QuillEditorState>( final editor = state<QuillEditorState>(
find.descendant( find.descendant(
of: finder, of: finder,
matching: find.byType(QuillEditor, skipOffstage: finder.skipOffstage), matching: find.byType(
QuillEditor,
skipOffstage: finder.skipOffstage,
),
matchRoot: true, matchRoot: true,
), ),
); );
editor.widget.focusNode.requestFocus(); editor.widget.focusNode.requestFocus();
await pump(); await pump();
expect(editor.widget.focusNode.hasFocus, isTrue); expect(
editor.widget.focusNode.hasFocus,
isTrue,
);
}); });
} }
@ -26,6 +34,7 @@ extension QuillEnterText on WidgetTester {
/// ///
/// The widget specified by [finder] must be a [QuillEditor] or have a /// The widget specified by [finder] must be a [QuillEditor] or have a
/// [QuillEditor] descendant. For example `find.byType(QuillEditor)`. /// [QuillEditor] descendant. For example `find.byType(QuillEditor)`.
///
Future<void> quillEnterText(Finder finder, String text) async { Future<void> quillEnterText(Finder finder, String text) async {
return TestAsyncUtils.guard(() async { return TestAsyncUtils.guard(() async {
await quillGiveFocus(finder); await quillGiveFocus(finder);
@ -40,19 +49,24 @@ extension QuillEnterText on WidgetTester {
/// The widget specified by [finder] must already have focus and be a /// The widget specified by [finder] must already have focus and be a
/// [QuillEditor] or have a [QuillEditor] descendant. For example /// [QuillEditor] or have a [QuillEditor] descendant. For example
/// `find.byType(QuillEditor)`. /// `find.byType(QuillEditor)`.
///
Future<void> quillUpdateEditingValue(Finder finder, String text) async { Future<void> quillUpdateEditingValue(Finder finder, String text) async {
return TestAsyncUtils.guard(() async { return TestAsyncUtils.guard(() async {
final editor = state<QuillRawEditorState>( final editor = state<QuillRawEditorState>(
find.descendant( find.descendant(
of: finder, of: finder,
matching: matching:
find.byType(QuillRawEditor, skipOffstage: finder.skipOffstage), find.byType(QuillRawEditor, skipOffstage: finder.skipOffstage),
matchRoot: true), matchRoot: true,
),
); );
testTextInput.updateEditingValue(TextEditingValue( testTextInput.updateEditingValue(
TextEditingValue(
text: text, text: text,
selection: TextSelection.collapsed( selection: TextSelection.collapsed(
offset: editor.textEditingValue.text.length))); offset: editor.textEditingValue.text.length),
),
);
await idle(); await idle();
}); });
} }

@ -26,12 +26,12 @@ environment:
dependencies: dependencies:
flutter: flutter:
sdk: flutter sdk: flutter
flutter_quill: ^8.2.2 flutter_quill: ^8.2.3
flutter_test: flutter_test:
sdk: flutter sdk: flutter
dev_dependencies: dev_dependencies:
flutter_lints: ^2.0.0 flutter_lints: ^3.0.1
# In case you are working on changes for both libraries # In case you are working on changes for both libraries
# Comment the dependency_overrides section when publishing the package, # Comment the dependency_overrides section when publishing the package,

@ -1 +1,2 @@
/// This will be empty for now
void main() {} void main() {}

@ -0,0 +1,68 @@
import 'dart:async' show Zone;
import 'dart:developer' as dev show log;
import 'package:flutter/foundation.dart' show kDebugMode;
import 'package:meta/meta.dart' show immutable;
/// Simple logger for the quill libraries
///
/// it log only if [kDebugMode] is true
/// so only for development mode and not in production
///
@immutable
class QuillLogger {
const QuillLogger._();
static bool shouldLog() {
return kDebugMode;
}
static void log<T>(
T message, {
DateTime? time,
int? sequenceNumber,
int level = 0,
String name = '',
Zone? zone,
StackTrace? stackTrace,
}) {
if (!shouldLog()) {
return;
}
dev.log(
message.toString(),
time: time,
sequenceNumber: sequenceNumber,
level: level,
name: name,
zone: zone,
stackTrace: stackTrace,
);
}
static void error<T>(
T message, {
DateTime? time,
int? sequenceNumber,
int level = 0,
String name = '',
Zone? zone,
Object? error,
StackTrace? stackTrace,
}) {
if (!shouldLog()) {
return;
}
dev.log(
message.toString(),
time: time,
sequenceNumber: sequenceNumber,
level: level,
name: name,
zone: zone,
error: error,
stackTrace: stackTrace,
);
}
}

@ -78,7 +78,7 @@ class RenderBaselineProxy extends RenderProxyBox {
} }
class EmbedProxy extends SingleChildRenderObjectWidget { class EmbedProxy extends SingleChildRenderObjectWidget {
const EmbedProxy(Widget child) : super(child: child); const EmbedProxy(Widget child, {super.key}) : super(child: child);
@override @override
RenderEmbedProxy createRenderObject(BuildContext context) => RenderEmbedProxy createRenderObject(BuildContext context) =>

@ -1164,9 +1164,10 @@ class QuillRawEditorState extends EditorState
} }
Future<void> _requestAutoFocusIfShould() async { Future<void> _requestAutoFocusIfShould() async {
final focusManager = FocusScope.of(context);
if (!_didAutoFocus && widget.autoFocus) { if (!_didAutoFocus && widget.autoFocus) {
await Future.delayed(Duration.zero); // To avoid exceptions await Future.delayed(Duration.zero); // To avoid exceptions
FocusScope.of(context).autofocus(widget.focusNode); focusManager.autofocus(widget.focusNode);
_didAutoFocus = true; _didAutoFocus = true;
} }
} }

@ -79,11 +79,11 @@ class QuillEditorCheckboxPointState extends State<QuillEditorCheckboxPoint> {
if (context.requireQuillSharedConfigurations.animationConfigurations if (context.requireQuillSharedConfigurations.animationConfigurations
.checkBoxPointItem) { .checkBoxPointItem) {
return Animate( return Animate(
effects: [ effects: const [
const SlideEffect( SlideEffect(
duration: Duration(milliseconds: 70), duration: Duration(milliseconds: 70),
), ),
const ScaleEffect( ScaleEffect(
duration: Duration(milliseconds: 70), duration: Duration(milliseconds: 70),
) )
], ],

@ -508,19 +508,19 @@ class _TextLineState extends State<TextLine> {
class EditableTextLine extends RenderObjectWidget { class EditableTextLine extends RenderObjectWidget {
const EditableTextLine( const EditableTextLine(
this.line, this.line,
this.leading, this.leading,
this.body, this.body,
this.indentWidth, this.indentWidth,
this.verticalSpacing, this.verticalSpacing,
this.textDirection, this.textDirection,
this.textSelection, this.textSelection,
this.color, this.color,
this.enableInteractiveSelection, this.enableInteractiveSelection,
this.hasFocus, this.hasFocus,
this.devicePixelRatio, this.devicePixelRatio,
this.cursorCont, this.cursorCont,
); {super.key});
final Line line; final Line line;
final Widget? leading; final Widget? leading;

@ -102,12 +102,12 @@ class QuillToolbarDivider extends StatelessWidget {
}); });
/// Provides a horizontal divider for vertical toolbar. /// Provides a horizontal divider for vertical toolbar.
const QuillToolbarDivider.horizontal({Color? color, double? space}) const QuillToolbarDivider.horizontal({Key? key, Color? color, double? space})
: this(Axis.horizontal, color: color, space: space); : this(Axis.horizontal, color: color, space: space, key: key);
/// Provides a horizontal divider for horizontal toolbar. /// Provides a horizontal divider for horizontal toolbar.
const QuillToolbarDivider.vertical({Color? color, double? space}) const QuillToolbarDivider.vertical({Key? key, Color? color, double? space})
: this(Axis.vertical, color: color, space: space); : this(Axis.vertical, color: color, space: space, key: key);
/// The axis along which the toolbar is. /// The axis along which the toolbar is.
final Axis axis; final Axis axis;

@ -281,7 +281,7 @@ class _LinkDialogState extends State<_LinkDialog> {
onChanged: _textChanged, onChanged: _textChanged,
controller: _textController, controller: _textController,
textInputAction: TextInputAction.next, textInputAction: TextInputAction.next,
autofillHints: [ autofillHints: const [
AutofillHints.name, AutofillHints.name,
AutofillHints.url, AutofillHints.url,
], ],
@ -299,7 +299,7 @@ class _LinkDialogState extends State<_LinkDialog> {
onChanged: _linkChanged, onChanged: _linkChanged,
controller: _linkController, controller: _linkController,
textInputAction: TextInputAction.done, textInputAction: TextInputAction.done,
autofillHints: [AutofillHints.url], autofillHints: const [AutofillHints.url],
autocorrect: false, autocorrect: false,
onEditingComplete: () { onEditingComplete: () {
if (!_canPress()) { if (!_canPress()) {

@ -9,6 +9,7 @@ class QuillProvider extends InheritedWidget {
const QuillProvider({ const QuillProvider({
required this.configurations, required this.configurations,
required super.child, required super.child,
super.key,
}); });
/// Controller object which establishes a link between a rich text document /// Controller object which establishes a link between a rich text document
@ -67,6 +68,7 @@ class QuillToolbarProvider extends InheritedWidget {
const QuillToolbarProvider({ const QuillToolbarProvider({
required super.child, required super.child,
required this.toolbarConfigurations, required this.toolbarConfigurations,
super.key,
}); });
/// The configurations for the toolbar widget of flutter quill /// The configurations for the toolbar widget of flutter quill
@ -124,6 +126,7 @@ class QuillBaseToolbarProvider extends InheritedWidget {
const QuillBaseToolbarProvider({ const QuillBaseToolbarProvider({
required super.child, required super.child,
required this.toolbarConfigurations, required this.toolbarConfigurations,
super.key,
}); });
/// The configurations for the toolbar widget of flutter quill /// The configurations for the toolbar widget of flutter quill
@ -181,6 +184,7 @@ class QuillEditorProvider extends InheritedWidget {
const QuillEditorProvider({ const QuillEditorProvider({
required super.child, required super.child,
required this.editorConfigurations, required this.editorConfigurations,
super.key,
}); });
/// The configurations for the quill editor widget of flutter quill /// The configurations for the quill editor widget of flutter quill

@ -1,6 +1,6 @@
name: flutter_quill 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. 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: 8.2.3 version: 8.2.4
homepage: https://1o24bbs.com/c/bulletjournal/108 homepage: https://1o24bbs.com/c/bulletjournal/108
repository: https://github.com/singerdmx/flutter-quill repository: https://github.com/singerdmx/flutter-quill
@ -54,7 +54,7 @@ dependencies:
flutter: flutter:
uses-material-design: true uses-material-design: true
dev_dependencies: dev_dependencies:
lints: ^3.0.0 flutter_lints: ^3.0.1
flutter_test: flutter_test:
sdk: flutter sdk: flutter
flutter_quill_test: ^0.0.2 flutter_quill_test: ^0.0.2

Loading…
Cancel
Save