Skip to content

Commit

Permalink
Update text selection when toggling checkbox (#441)
Browse files Browse the repository at this point in the history
  • Loading branch information
amantoux authored Jan 3, 2025
1 parent 4c3d05a commit 0240e29
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 7 deletions.
19 changes: 15 additions & 4 deletions packages/fleather/lib/src/widgets/controller.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ import '../../util.dart';
import 'autoformats.dart';
import 'history.dart';

/// List of style keys which can be toggled for insertion
/// @docImport 'checkbox.dart';
// List of style keys which can be toggled for insertion
List<String> _toggleableStyleKeys = [
ParchmentAttribute.bold.key,
ParchmentAttribute.italic.key,
Expand All @@ -34,7 +36,7 @@ class FleatherController extends ChangeNotifier {

ParchmentDocument _document;

/// Doument managed by this controller.
/// Document managed by this controller.
ParchmentDocument get document => _document;

// A list of changes applied to this doc. The changes could be undone or redone.
Expand Down Expand Up @@ -206,7 +208,16 @@ class FleatherController extends ChangeNotifier {
return true;
}

void formatText(int index, int length, ParchmentAttribute attribute) {
/// Update format of [length] characters in the document starting at [index]
/// with the provided [attribute].
///
/// If [notify] is `true`, the controller will notify widgets to update
/// accordingly; otherwise widgets will not update, this is useful when
/// we do not want a widget to update the document without triggering a
/// rebuild if the editor (e.g.: [FleatherCheckbox] toggling should not cause
/// scrolling to cursor).
void formatText(int index, int length, ParchmentAttribute attribute,
{bool notify = true}) {
final change = document.format(index, length, attribute);
// _lastChangeSource = ChangeSource.local;
const source = ChangeSource.local;
Expand All @@ -227,7 +238,7 @@ class FleatherController extends ChangeNotifier {
_updateSelectionSilent(adjustedSelection, source: source);
}
_updateHistory();
notifyListeners();
if (notify) notifyListeners();
}

/// Formats current selection with [attribute].
Expand Down
26 changes: 23 additions & 3 deletions packages/fleather/lib/src/widgets/editable_text_block.dart
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ class EditableTextBlock extends StatelessWidget {
void _toggle(LineNode node, bool checked) {
final attr =
checked ? ParchmentAttribute.checked : ParchmentAttribute.checked.unset;
controller.formatText(node.documentOffset, 0, attr);
controller.formatText(node.documentOffset, 0, attr, notify: false);
}
}

Expand Down Expand Up @@ -347,7 +347,7 @@ class _BulletPoint extends StatelessWidget {
}
}

class _CheckboxPoint extends StatelessWidget {
class _CheckboxPoint extends StatefulWidget {
const _CheckboxPoint({
required this.value,
required this.enabled,
Expand All @@ -358,14 +358,34 @@ class _CheckboxPoint extends StatelessWidget {
final bool enabled;
final ValueChanged<bool> onChanged;

@override
State<_CheckboxPoint> createState() => _CheckboxPointState();
}

class _CheckboxPointState extends State<_CheckboxPoint> {
late bool value = widget.value;

@override
void didUpdateWidget(covariant _CheckboxPoint oldWidget) {
super.didUpdateWidget(oldWidget);
if (value != widget.value) {
setState(() => value = widget.value);
}
}

@override
Widget build(BuildContext context) {
return Container(
alignment: AlignmentDirectional.topEnd,
padding: const EdgeInsetsDirectional.only(top: 2.0, end: 12.0),
child: FleatherCheckbox(
value: value,
onChanged: enabled ? (_) => onChanged(!value) : null,
onChanged: widget.enabled
? (_) {
widget.onChanged(!value);
setState(() => value = !value);
}
: null,
),
);
}
Expand Down
23 changes: 23 additions & 0 deletions packages/fleather/test/widgets/editable_text_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,29 @@ void main() {
Operation.insert('\n', {'block': 'cl', 'checked': true}));
});

testWidgets('check list toggle', (tester) async {
const textPrecedingCheckBox = 'some text\n';
final delta = Delta()
..insert(textPrecedingCheckBox)
..insert('an item')
..insert('\n', {'block': 'cl'});
final editor = EditorSandBox(
tester: tester, document: ParchmentDocument.fromDelta(delta));
await editor.pump();
expect(find.byType(FleatherCheckbox), findsOneWidget);
await editor.updateSelection(base: 0, extent: 0);

editor.controller.addListener(() {
fail('Controller should not notify when checkbox is toggled');
});
await tester.tap(find.byType(FleatherCheckbox));
await tester.pumpAndSettle(throttleDuration);
expect(editor.document.toDelta().last,
Operation.insert('\n', {'block': 'cl', 'checked': true}));
expect(editor.controller.selection,
const TextSelection.collapsed(offset: 0));
});

testWidgets('bullet list', (tester) async {
final delta = Delta()
..insert('an item')
Expand Down

0 comments on commit 0240e29

Please sign in to comment.