Skip to content

Fix: Issue with single character formatting in the toggle style button . #2597

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
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
11 changes: 2 additions & 9 deletions lib/src/toolbar/buttons/toggle_style_button.dart
Original file line number Diff line number Diff line change
Expand Up @@ -135,15 +135,8 @@ class QuillToolbarToggleStyleButtonState
}

bool _getIsToggled(Map<String, Attribute> attrs) {
if (widget.attribute.key == Attribute.list.key ||
widget.attribute.key == Attribute.header.key ||
widget.attribute.key == Attribute.script.key ||
widget.attribute.key == Attribute.align.key) {
final attribute = attrs[widget.attribute.key];
if (attribute == null) {
return false;
}
return attribute.value == widget.attribute.value;
if (controller.selection.end - controller.selection.start == 1) {
return false;
}
return attrs.containsKey(widget.attribute.key);
}
Expand Down
53 changes: 15 additions & 38 deletions test/common/utils/quill_test_app.dart
Original file line number Diff line number Diff line change
Expand Up @@ -35,61 +35,38 @@ class QuillTestApp extends StatelessWidget {
///
/// Either [home] or [scaffoldBody] must be provided.
/// Throws an [ArgumentError] if both are provided.
QuillTestApp({
required this.home,
required this.scaffoldBody,
this.onLocalizationsAvailable,
const QuillTestApp({
required this.child,
super.key,
}) {
if (home != null && scaffoldBody != null) {
throw ArgumentError('Either the home or scaffoldBody must be null');
}
}
});

/// Creates a [QuillTestApp] with a [Scaffold] wrapping the given [body] widget.
factory QuillTestApp.withScaffold(Widget body,
{LocalizationsAvailableCallback? onLocalizationsAvailable}) =>
QuillTestApp(
home: null,
scaffoldBody: body,
onLocalizationsAvailable: onLocalizationsAvailable,
);
static Widget withScaffold(Widget child) {
return MaterialApp(
localizationsDelegates: FlutterQuillLocalizations.localizationsDelegates,
supportedLocales: FlutterQuillLocalizations.supportedLocales,
home: Scaffold(
body: child,
),
);
}

/// Creates a [QuillTestApp] with the specified [home] widget.
factory QuillTestApp.home(Widget home,
{LocalizationsAvailableCallback? onLocalizationsAvailable}) =>
QuillTestApp(
home: home,
scaffoldBody: null,
onLocalizationsAvailable: onLocalizationsAvailable,
child: home,
);

/// The home widget for the application.
///
/// If [home] is not null, [scaffoldBody] must be null.
final Widget? home;

/// The body widget for a [Scaffold] used as the application home.
///
/// If [scaffoldBody] is not null, [home] must be null.
final Widget? scaffoldBody;

final LocalizationsAvailableCallback? onLocalizationsAvailable;
final Widget child;

@override
Widget build(BuildContext context) {
return MaterialApp(
localizationsDelegates: FlutterQuillLocalizations.localizationsDelegates,
supportedLocales: FlutterQuillLocalizations.supportedLocales,
home: Builder(builder: (context) {
if (onLocalizationsAvailable != null) {
onLocalizationsAvailable?.call(context.loc);
}
return home ??
Scaffold(
body: scaffoldBody,
);
}),
home: child,
);
}
}
Expand Down
72 changes: 72 additions & 0 deletions test/toolbar/buttons/toggle_style_button_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import 'package:flutter/material.dart';
import 'package:flutter_quill/flutter_quill.dart';
import 'package:flutter_test/flutter_test.dart';

import '../../common/utils/quill_test_app.dart';

void main() {
group('QuillToolbarToggleStyleButton', () {
testWidgets('should not toggle toolbar state when formatting single character',
(tester) async {
final controller = QuillController.basic();
controller.document.insert(0, 'Hello World');

await tester.pumpWidget(
QuillTestApp.withScaffold(
QuillToolbarToggleStyleButton(
controller: controller,
attribute: Attribute.bold,
),
),
);

// Format a single character
controller.formatText(0, 1, Attribute.bold);

// Verify the toolbar button is not toggled
final button = tester.widget<QuillToolbarIconButton>(
find.byType(QuillToolbarIconButton),
);
expect(button.isSelected, false);

// Format multiple characters
controller.formatText(0, 5, Attribute.bold);

// Verify the toolbar button is now toggled
await tester.pump();
final buttonAfterMultiFormat = tester.widget<QuillToolbarIconButton>(
find.byType(QuillToolbarIconButton),
);
expect(buttonAfterMultiFormat.isSelected, true);
});

testWidgets('should maintain formatting for single character',
(tester) async {
final controller = QuillController.basic();
controller.document.insert(0, 'Hello World');

await tester.pumpWidget(
QuillTestApp.withScaffold(
QuillToolbarToggleStyleButton(
controller: controller,
attribute: Attribute.bold,
),
),
);

// Format a single character
controller.formatText(0, 1, Attribute.bold);

// Verify the character is bold
final style = controller.document.collectStyle(0, 1);
expect(style.attributes.containsKey(Attribute.bold.key), true);

// Type new text after the bold character
controller.replaceText(1, 0, 'New text', null);

// Verify the new text is not bold
final newStyle = controller.document.collectStyle(1, 9);
expect(newStyle.attributes.containsKey(Attribute.bold.key), false);
});
});
}