Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .git-blame-ignore-revs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Revisions for `git blame` to skip (large, mechanical changes with no logic impact).
#
# Enable locally once with:
# git config blame.ignoreRevsFile .git-blame-ignore-revs
#
# GitHub honors this file automatically. List full 40-char commit SHAs only.

# style: apply Dart 3.12 format (tall style) — repo-wide dart_format, no logic changes
10e0814088ae3b12f0cca4673f885e2828eaaa7a
9 changes: 6 additions & 3 deletions .github/workflows/checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ jobs:
- name: Set up Flutter
uses: subosito/flutter-action@v2
with:
# Pinned so a future Flutter/Dart release can't change formatter output
# and turn the format check below red on unrelated PRs. Bump deliberately
# alongside a repo-wide reformat (see .git-blame-ignore-revs).
flutter-version: 3.44.1
channel: stable
cache: true

Expand All @@ -34,9 +38,8 @@ jobs:
- name: Perform Flutter Analysis
run: flutter analyze

# TODO: Restore Dart formatting check, disabled due to an issue https://github.com/singerdmx/flutter-quill/actions/runs/13355109619/job/37296760819.
# - name: Check Dart code formatting
# run: dart format --set-exit-if-changed .
- name: Check Dart code formatting
run: dart format --set-exit-if-changed .

- name: Preview Dart proposed changes
run: dart fix --dry-run
Expand Down
11 changes: 6 additions & 5 deletions example/integration_test/flutter_quill_integration_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,18 @@ import 'package:integration_test/integration_test.dart';
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();

testWidgets('$QuillEditor renders and handles input without crashing',
(tester) async {
testWidgets('$QuillEditor renders and handles input without crashing', (
tester,
) async {
// This test ensures that the QuillEditor can be created and accepts input
// without crashing on any platform.
//
// Example fix: https://github.com/singerdmx/flutter-quill/pull/2579

final controller = QuillController.basic();
await tester.pumpWidget(MaterialApp(
home: QuillEditor.basic(controller: controller),
));
await tester.pumpWidget(
MaterialApp(home: QuillEditor.basic(controller: controller)),
);

// Simulate text input to trigger user interactions.
await tester.quillEnterText(find.byType(QuillEditor), 'sample text\n');
Expand Down
54 changes: 12 additions & 42 deletions example/lib/custom_toolbar.dart
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,8 @@ class CustomToolbar extends StatelessWidget {
scrollDirection: Axis.horizontal,
child: Wrap(
children: [
QuillToolbarHistoryButton(
isUndo: true,
controller: controller,
),
QuillToolbarHistoryButton(
isUndo: false,
controller: controller,
),
QuillToolbarHistoryButton(isUndo: true, controller: controller),
QuillToolbarHistoryButton(isUndo: false, controller: controller),
QuillToolbarToggleStyleButton(
options: const QuillToolbarToggleStyleButtonOptions(),
controller: controller,
Expand All @@ -38,40 +32,22 @@ class CustomToolbar extends StatelessWidget {
controller: controller,
attribute: Attribute.underline,
),
QuillToolbarClearFormatButton(
controller: controller,
),
QuillToolbarClearFormatButton(controller: controller),
const VerticalDivider(),
QuillToolbarImageButton(
controller: controller,
),
QuillToolbarCameraButton(
controller: controller,
),
QuillToolbarVideoButton(
controller: controller,
),
QuillToolbarImageButton(controller: controller),
QuillToolbarCameraButton(controller: controller),
QuillToolbarVideoButton(controller: controller),
const VerticalDivider(),
QuillToolbarColorButton(
controller: controller,
isBackground: false,
),
QuillToolbarColorButton(
controller: controller,
isBackground: true,
),
QuillToolbarColorButton(controller: controller, isBackground: false),
QuillToolbarColorButton(controller: controller, isBackground: true),
const VerticalDivider(),
QuillToolbarSelectHeaderStyleDropdownButton(
controller: controller,
),
QuillToolbarSelectHeaderStyleDropdownButton(controller: controller),
const VerticalDivider(),
QuillToolbarSelectLineHeightStyleDropdownButton(
controller: controller,
),
const VerticalDivider(),
QuillToolbarToggleCheckListButton(
controller: controller,
),
QuillToolbarToggleCheckListButton(controller: controller),
QuillToolbarToggleStyleButton(
controller: controller,
attribute: Attribute.ol,
Expand All @@ -88,14 +64,8 @@ class CustomToolbar extends StatelessWidget {
controller: controller,
attribute: Attribute.blockQuote,
),
QuillToolbarIndentButton(
controller: controller,
isIncrease: true,
),
QuillToolbarIndentButton(
controller: controller,
isIncrease: false,
),
QuillToolbarIndentButton(controller: controller, isIncrease: true),
QuillToolbarIndentButton(controller: controller, isIncrease: false),
const VerticalDivider(),
QuillToolbarLinkStyleButton(controller: controller),
],
Expand Down
70 changes: 34 additions & 36 deletions example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -42,29 +42,30 @@ class HomePage extends StatefulWidget {
class _HomePageState extends State<HomePage> {
final QuillController _controller = () {
return QuillController.basic(
config: QuillControllerConfig(
clipboardConfig: QuillClipboardConfig(
enableExternalRichPaste: true,
onImagePaste: (imageBytes) async {
if (kIsWeb) {
// Dart IO is unsupported on the web.
return null;
}
// Save the image somewhere and return the image URL that will be
// stored in the Quill Delta JSON (the document).
final newFileName =
'image-file-${DateTime.now().toIso8601String()}.png';
final newPath = path.join(
io.Directory.systemTemp.path,
newFileName,
);
final file = await io.File(
newPath,
).writeAsBytes(imageBytes, flush: true);
return file.path;
},
config: QuillControllerConfig(
clipboardConfig: QuillClipboardConfig(
enableExternalRichPaste: true,
onImagePaste: (imageBytes) async {
if (kIsWeb) {
// Dart IO is unsupported on the web.
return null;
}
// Save the image somewhere and return the image URL that will be
// stored in the Quill Delta JSON (the document).
final newFileName =
'image-file-${DateTime.now().toIso8601String()}.png';
final newPath = path.join(
io.Directory.systemTemp.path,
newFileName,
);
final file = await io.File(
newPath,
).writeAsBytes(imageBytes, flush: true);
return file.path;
},
),
),
));
);
}();
final FocusNode _editorFocusNode = FocusNode();
final ScrollController _editorScrollController = ScrollController();
Expand All @@ -86,9 +87,13 @@ class _HomePageState extends State<HomePage> {
icon: const Icon(Icons.output),
tooltip: 'Print Delta JSON to log',
onPressed: () {
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(
content:
Text('The JSON Delta has been printed to the console.')));
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text(
'The JSON Delta has been printed to the console.',
),
),
);
debugPrint(jsonEncode(_controller.document.toDelta().toJson()));
},
),
Expand All @@ -108,9 +113,7 @@ class _HomePageState extends State<HomePage> {
onPressed: () {
_controller.document.insert(
_controller.selection.extentOffset,
TimeStampEmbed(
DateTime.now().toString(),
),
TimeStampEmbed(DateTime.now().toString()),
);

_controller.updateSelection(
Expand All @@ -128,7 +131,7 @@ class _HomePageState extends State<HomePage> {
final isDesktop = {
TargetPlatform.linux,
TargetPlatform.windows,
TargetPlatform.macOS
TargetPlatform.macOS,
}.contains(defaultTargetPlatform);
if (isDesktop) {
_editorFocusNode.requestFocus();
Expand Down Expand Up @@ -193,9 +196,7 @@ class _HomePageState extends State<HomePage> {
}

class TimeStampEmbed extends Embeddable {
const TimeStampEmbed(
String value,
) : super(timeStampType, value);
const TimeStampEmbed(String value) : super(timeStampType, value);

static const String timeStampType = 'timeStamp';

Expand All @@ -215,10 +216,7 @@ class TimeStampEmbedBuilder extends EmbedBuilder {
}

@override
Widget build(
BuildContext context,
EmbedContext embedContext,
) {
Widget build(BuildContext context, EmbedContext embedContext) {
return Row(
children: [
const Icon(Icons.access_time_rounded),
Expand Down
Loading
Loading