Skip to content
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

Add clear controller feature #393

Merged
merged 2 commits into from
Aug 8, 2024
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
38 changes: 33 additions & 5 deletions packages/fleather/lib/src/widgets/controller.dart
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ List<String> _toggleableStyleKeys = [

class FleatherController extends ChangeNotifier {
FleatherController({ParchmentDocument? document, AutoFormats? autoFormats})
: document = document ?? ParchmentDocument(),
: _document = document ?? ParchmentDocument(),
_history = HistoryStack.doc(document),
_autoFormats = autoFormats ?? AutoFormats.fallback(),
_selection = const TextSelection.collapsed(offset: 0) {
Expand All @@ -33,13 +33,15 @@ class FleatherController extends ChangeNotifier {
);
}

/// Document managed by this controller.
final ParchmentDocument document;
ParchmentDocument _document;

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

// A list of changes applied to this doc. The changes could be undone or redone.
final HistoryStack _history;
HistoryStack _history;

late final _Throttled<Delta> _throttledPush;
late _Throttled<Delta> _throttledPush;
Timer? _throttleTimer;

// The auto format handler
Expand Down Expand Up @@ -311,6 +313,32 @@ class FleatherController extends ChangeNotifier {
composing: TextRange.empty,
);
}

/// Clear the controller state.
///
/// It creates a new empty [ParchmentDocument] and a clean edit history.
/// The old [document] will be closed if [closeDocument] is true.
///
/// Calling this will notify all the listeners of this [FleatherController]
/// that they need to update (it calls [notifyListeners]). For this reason,
/// this method should only be called between frames, e.g. in response to user
/// actions, not during the build, layout, or paint phases.
void clear({bool closeDocument = true}) {
_throttleTimer?.cancel();
_toggledStyles = ParchmentStyle();
_selection = const TextSelection.collapsed(offset: 0);
_autoFormats.cancelActive();
if (closeDocument) {
document.close();
}
_document = ParchmentDocument();
_history = HistoryStack.doc(document);
_throttledPush = _throttle(
duration: throttleDuration,
function: _history.push,
);
notifyListeners();
}
}

// This duration was chosen as a best fit for the behavior of Mac, Linux,
Expand Down
44 changes: 44 additions & 0 deletions packages/fleather/test/widgets/controller_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,50 @@ void main() {
// expect(controller.lastChangeSource, ChangeSource.local);
});

group('clear', () {
test('closes the document by default', () {
fakeAsync((async) {
final doc = controller.document;
controller.compose(Delta()..insert('word'),
selection: const TextSelection.collapsed(offset: 4));
async.flushTimers();
var notified = false;
controller.addListener(() => notified = true);
controller.clear();
expect(identical(controller.document, doc), isFalse);
expect(controller.document.toDelta(), Delta()..insert('\n'));
expect(doc.isClosed, isTrue);
expect(
controller.selection, const TextSelection.collapsed(offset: 0));
expect(controller.canUndo, isFalse);
expect(controller.canRedo, isFalse);
expect(controller.toggledStyles, ParchmentStyle());
expect(notified, isTrue);
});
});

test('closeDocument is false', () {
fakeAsync((async) {
final doc = controller.document;
controller.compose(Delta()..insert('word'),
selection: const TextSelection.collapsed(offset: 4));
async.flushTimers();
var notified = false;
controller.addListener(() => notified = true);
controller.clear(closeDocument: false);
expect(identical(controller.document, doc), isFalse);
expect(controller.document.toDelta(), Delta()..insert('\n'));
expect(doc.isClosed, isFalse);
expect(
controller.selection, const TextSelection.collapsed(offset: 0));
expect(controller.canUndo, isFalse);
expect(controller.canRedo, isFalse);
expect(controller.toggledStyles, ParchmentStyle());
expect(notified, isTrue);
});
});
});

group('history', () {
group('empty stack', () {
test('undo returns null', () {
Expand Down
Loading