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