feat: support in memory transaction update (#972)
* feat: support in memory transaction update * test: support in memory transaction update
This commit is contained in:
parent
6009429e58
commit
5b3878dcc5
3 changed files with 41 additions and 15 deletions
|
|
@ -8,6 +8,12 @@ import 'package:appflowy_editor/src/history/undo_manager.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
typedef EditorTransactionValue = (
|
||||||
|
TransactionTime time,
|
||||||
|
Transaction transaction,
|
||||||
|
ApplyOptions options,
|
||||||
|
);
|
||||||
|
|
||||||
/// the type of this value is bool.
|
/// the type of this value is bool.
|
||||||
///
|
///
|
||||||
/// set true to this key to prevent attaching the text service when selection is changed.
|
/// set true to this key to prevent attaching the text service when selection is changed.
|
||||||
|
|
@ -15,15 +21,20 @@ const selectionExtraInfoDoNotAttachTextService =
|
||||||
'selectionExtraInfoDoNotAttachTextService';
|
'selectionExtraInfoDoNotAttachTextService';
|
||||||
|
|
||||||
class ApplyOptions {
|
class ApplyOptions {
|
||||||
|
const ApplyOptions({
|
||||||
|
this.recordUndo = true,
|
||||||
|
this.recordRedo = false,
|
||||||
|
this.inMemoryUpdate = false,
|
||||||
|
});
|
||||||
|
|
||||||
/// This flag indicates that
|
/// This flag indicates that
|
||||||
/// whether the transaction should be recorded into
|
/// whether the transaction should be recorded into
|
||||||
/// the undo stack
|
/// the undo stack
|
||||||
final bool recordUndo;
|
final bool recordUndo;
|
||||||
final bool recordRedo;
|
final bool recordRedo;
|
||||||
const ApplyOptions({
|
|
||||||
this.recordUndo = true,
|
/// This flag used to determine whether the transaction is in-memory update.
|
||||||
this.recordRedo = false,
|
final bool inMemoryUpdate;
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Deprecated('use SelectionUpdateReason instead')
|
@Deprecated('use SelectionUpdateReason instead')
|
||||||
|
|
@ -172,9 +183,8 @@ class EditorState {
|
||||||
List<ToolbarItem> toolbarItems = [];
|
List<ToolbarItem> toolbarItems = [];
|
||||||
|
|
||||||
/// listen to this stream to get notified when the transaction applies.
|
/// listen to this stream to get notified when the transaction applies.
|
||||||
Stream<(TransactionTime, Transaction)> get transactionStream =>
|
Stream<EditorTransactionValue> get transactionStream => _observer.stream;
|
||||||
_observer.stream;
|
final StreamController<EditorTransactionValue> _observer =
|
||||||
final StreamController<(TransactionTime, Transaction)> _observer =
|
|
||||||
StreamController.broadcast(sync: true);
|
StreamController.broadcast(sync: true);
|
||||||
|
|
||||||
/// Store the toggled format style, like bold, italic, etc.
|
/// Store the toggled format style, like bold, italic, etc.
|
||||||
|
|
@ -337,14 +347,14 @@ class EditorState {
|
||||||
} else {
|
} else {
|
||||||
// broadcast to other users here, before applying the transaction
|
// broadcast to other users here, before applying the transaction
|
||||||
if (!_observer.isClosed) {
|
if (!_observer.isClosed) {
|
||||||
_observer.add((TransactionTime.before, transaction));
|
_observer.add((TransactionTime.before, transaction, options));
|
||||||
}
|
}
|
||||||
|
|
||||||
_applyTransactionInLocal(transaction);
|
_applyTransactionInLocal(transaction);
|
||||||
|
|
||||||
// broadcast to other users here, after applying the transaction
|
// broadcast to other users here, after applying the transaction
|
||||||
if (!_observer.isClosed) {
|
if (!_observer.isClosed) {
|
||||||
_observer.add((TransactionTime.after, transaction));
|
_observer.add((TransactionTime.after, transaction, options));
|
||||||
}
|
}
|
||||||
|
|
||||||
_recordRedoOrUndo(options, transaction, skipHistoryDebounce);
|
_recordRedoOrUndo(options, transaction, skipHistoryDebounce);
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:flutter/widgets.dart';
|
|
||||||
|
|
||||||
import 'package:appflowy_editor/appflowy_editor.dart';
|
import 'package:appflowy_editor/appflowy_editor.dart';
|
||||||
|
import 'package:flutter/widgets.dart';
|
||||||
|
|
||||||
const _emptyCounters = Counters();
|
const _emptyCounters = Counters();
|
||||||
|
|
||||||
|
|
@ -99,7 +98,7 @@ class WordCountService with ChangeNotifier {
|
||||||
///
|
///
|
||||||
bool isRunning = false;
|
bool isRunning = false;
|
||||||
|
|
||||||
StreamSubscription<(TransactionTime, Transaction)>? _streamSubscription;
|
StreamSubscription<EditorTransactionValue>? _streamSubscription;
|
||||||
|
|
||||||
/// This method can be used to get the word and character
|
/// This method can be used to get the word and character
|
||||||
/// count of the [Document] of the [EditorState].
|
/// count of the [Document] of the [EditorState].
|
||||||
|
|
@ -221,9 +220,9 @@ class WordCountService with ChangeNotifier {
|
||||||
return Counters(wordCount: wordCount, charCount: charCount);
|
return Counters(wordCount: wordCount, charCount: charCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _onDocUpdate((TransactionTime time, Transaction t) event) {
|
void _onDocUpdate(EditorTransactionValue value) {
|
||||||
if (debounceDuration.inMilliseconds == 0) {
|
if (debounceDuration.inMilliseconds == 0) {
|
||||||
return _recountOnTransactionUpdate(event.$1);
|
return _recountOnTransactionUpdate(value.$1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_documentTimer?.isActive ?? false) {
|
if (_documentTimer?.isActive ?? false) {
|
||||||
|
|
@ -232,7 +231,7 @@ class WordCountService with ChangeNotifier {
|
||||||
|
|
||||||
_documentTimer = Timer(
|
_documentTimer = Timer(
|
||||||
debounceDuration,
|
debounceDuration,
|
||||||
() => _recountOnTransactionUpdate(event.$1),
|
() => _recountOnTransactionUpdate(value.$1),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -28,5 +28,22 @@ void main() async {
|
||||||
await editorState.apply(transaction);
|
await editorState.apply(transaction);
|
||||||
expect(count, 2);
|
expect(count, 2);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('transaction stream', () async {
|
||||||
|
final editorState = EditorState.blank(
|
||||||
|
withInitialText: false,
|
||||||
|
);
|
||||||
|
var isInMemoryUpdate = false;
|
||||||
|
editorState.transactionStream.listen((event) {
|
||||||
|
isInMemoryUpdate = event.$3.inMemoryUpdate;
|
||||||
|
});
|
||||||
|
final transaction = editorState.transaction;
|
||||||
|
transaction.insertNode([0], paragraphNode(text: 'Hello World!'));
|
||||||
|
await editorState.apply(
|
||||||
|
transaction,
|
||||||
|
options: const ApplyOptions(inMemoryUpdate: true),
|
||||||
|
);
|
||||||
|
expect(isInMemoryUpdate, true);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue