mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2025-12-02 02:00:45 +00:00
fix: ai text insertion (#7615)
* fix: dont scroll to ai writer node if path not found * chore: rename text robot clear method and add reset * fix: insert position is off if using ai writer multiple times * chore: reorganize code * fix: undo not working after accept
This commit is contained in:
parent
eb4b015de8
commit
039c191d1f
@ -48,16 +48,16 @@ Future<void> removeAiWriterNode(
|
||||
);
|
||||
}
|
||||
|
||||
void formatSelection(
|
||||
Future<void> formatSelection(
|
||||
EditorState editorState,
|
||||
Selection selection,
|
||||
Transaction transaction,
|
||||
ApplySuggestionFormatType formatType,
|
||||
) {
|
||||
) async {
|
||||
final nodes = editorState.getNodesInSelection(selection).toList();
|
||||
if (nodes.isEmpty) {
|
||||
return;
|
||||
}
|
||||
final transaction = editorState.transaction;
|
||||
|
||||
if (nodes.length == 1) {
|
||||
final node = nodes.removeAt(0);
|
||||
@ -103,25 +103,43 @@ void formatSelection(
|
||||
}
|
||||
|
||||
transaction.compose();
|
||||
await editorState.apply(
|
||||
transaction,
|
||||
options: ApplyOptions(
|
||||
inMemoryUpdate: true,
|
||||
recordUndo: false,
|
||||
),
|
||||
withUpdateSelection: false,
|
||||
);
|
||||
}
|
||||
|
||||
Position ensurePreviousNodeIsEmptyParagraph(
|
||||
Future<Position> ensurePreviousNodeIsEmptyParagraph(
|
||||
EditorState editorState,
|
||||
Node aiWriterNode,
|
||||
Transaction transaction,
|
||||
) {
|
||||
) async {
|
||||
final previous = aiWriterNode.previous;
|
||||
final needsEmptyParagraphNode = previous == null ||
|
||||
previous.type != ParagraphBlockKeys.type ||
|
||||
(previous.delta?.toPlainText().isNotEmpty ?? false);
|
||||
|
||||
final Position position;
|
||||
final transaction = editorState.transaction;
|
||||
|
||||
if (needsEmptyParagraphNode) {
|
||||
position = Position(path: aiWriterNode.path);
|
||||
transaction.insertNode(aiWriterNode.path, paragraphNode());
|
||||
} else {
|
||||
position = Position(path: previous.path);
|
||||
}
|
||||
transaction.afterSelection = Selection.collapsed(position);
|
||||
|
||||
await editorState.apply(
|
||||
transaction,
|
||||
options: ApplyOptions(
|
||||
inMemoryUpdate: true,
|
||||
recordUndo: false,
|
||||
),
|
||||
);
|
||||
|
||||
return position;
|
||||
}
|
||||
|
||||
@ -54,6 +54,7 @@ class AiWriterCubit extends Cubit<AiWriterState> {
|
||||
if (withDiscard) {
|
||||
await _textRobot.discard();
|
||||
}
|
||||
_textRobot.clear();
|
||||
_textRobot.reset();
|
||||
onRemoveNode?.call();
|
||||
records.clear();
|
||||
@ -65,21 +66,11 @@ class AiWriterCubit extends Cubit<AiWriterState> {
|
||||
if (selection == null) {
|
||||
return;
|
||||
}
|
||||
final transaction = editorState.transaction;
|
||||
formatSelection(
|
||||
await formatSelection(
|
||||
editorState,
|
||||
selection,
|
||||
transaction,
|
||||
ApplySuggestionFormatType.clear,
|
||||
);
|
||||
await editorState.apply(
|
||||
transaction,
|
||||
options: const ApplyOptions(
|
||||
inMemoryUpdate: true,
|
||||
recordUndo: false,
|
||||
),
|
||||
withUpdateSelection: false,
|
||||
);
|
||||
}
|
||||
if (aiWriterNode != null) {
|
||||
await removeAiWriterNode(editorState, aiWriterNode!);
|
||||
@ -122,7 +113,7 @@ class AiWriterCubit extends Cubit<AiWriterState> {
|
||||
}
|
||||
|
||||
await _textRobot.discard();
|
||||
_textRobot.reset();
|
||||
_textRobot.clear();
|
||||
|
||||
switch (command) {
|
||||
case AiWriterCommand.continueWriting:
|
||||
@ -222,11 +213,15 @@ class AiWriterCubit extends Cubit<AiWriterState> {
|
||||
|
||||
if (action case SuggestionAction.accept) {
|
||||
await _textRobot.persist();
|
||||
await formatSelection(
|
||||
editorState,
|
||||
selection,
|
||||
ApplySuggestionFormatType.clear,
|
||||
);
|
||||
final nodes = editorState.getNodesInSelection(selection);
|
||||
final transaction = editorState.transaction..deleteNodes(nodes);
|
||||
await editorState.apply(
|
||||
transaction,
|
||||
options: const ApplyOptions(recordUndo: false),
|
||||
withUpdateSelection: false,
|
||||
);
|
||||
await exit(withDiscard: false, withUnformat: false);
|
||||
@ -235,6 +230,8 @@ class AiWriterCubit extends Cubit<AiWriterState> {
|
||||
|
||||
if (action case SuggestionAction.keep) {
|
||||
await _textRobot.persist();
|
||||
await exit(withDiscard: false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (action case SuggestionAction.insertBelow) {
|
||||
@ -244,20 +241,9 @@ class AiWriterCubit extends Cubit<AiWriterState> {
|
||||
final command = (state as ReadyAiWriterState).command;
|
||||
final markdownText = (state as ReadyAiWriterState).markdownText;
|
||||
if (command == AiWriterCommand.explain && markdownText.isNotEmpty) {
|
||||
final transaction = editorState.transaction;
|
||||
final position = ensurePreviousNodeIsEmptyParagraph(
|
||||
final position = await ensurePreviousNodeIsEmptyParagraph(
|
||||
editorState,
|
||||
aiWriterNode!,
|
||||
transaction,
|
||||
);
|
||||
transaction.afterSelection = null;
|
||||
await editorState.apply(
|
||||
transaction,
|
||||
options: ApplyOptions(
|
||||
inMemoryUpdate: true,
|
||||
recordUndo: false,
|
||||
),
|
||||
withUpdateSelection: false,
|
||||
);
|
||||
_textRobot.start(position: position);
|
||||
await _textRobot.persist(markdownText: markdownText);
|
||||
@ -265,21 +251,13 @@ class AiWriterCubit extends Cubit<AiWriterState> {
|
||||
await _textRobot.persist();
|
||||
}
|
||||
|
||||
final transaction = editorState.transaction;
|
||||
formatSelection(
|
||||
await formatSelection(
|
||||
editorState,
|
||||
selection,
|
||||
transaction,
|
||||
ApplySuggestionFormatType.clear,
|
||||
);
|
||||
await editorState.apply(
|
||||
transaction,
|
||||
options: const ApplyOptions(recordUndo: false),
|
||||
withUpdateSelection: false,
|
||||
);
|
||||
await exit(withDiscard: false);
|
||||
}
|
||||
|
||||
await exit(withDiscard: false);
|
||||
}
|
||||
|
||||
bool hasUnusedResponse() {
|
||||
@ -308,22 +286,20 @@ class AiWriterCubit extends Cubit<AiWriterState> {
|
||||
|
||||
if (command == AiWriterCommand.continueWriting) {
|
||||
return (true, '');
|
||||
} else {
|
||||
if (selection.isCollapsed) {
|
||||
return (true, '');
|
||||
} else {
|
||||
final selectionText =
|
||||
await editorState.getMarkdownInSelection(selection);
|
||||
}
|
||||
if (selection.isCollapsed) {
|
||||
return (true, '');
|
||||
}
|
||||
|
||||
if (command == AiWriterCommand.userQuestion) {
|
||||
records.add(
|
||||
AiWriterRecord.user(content: selectionText, format: null),
|
||||
);
|
||||
return (true, '');
|
||||
} else {
|
||||
return (true, selectionText);
|
||||
}
|
||||
}
|
||||
final selectionText = await editorState.getMarkdownInSelection(selection);
|
||||
|
||||
if (command == AiWriterCommand.userQuestion) {
|
||||
records.add(
|
||||
AiWriterRecord.user(content: selectionText, format: null),
|
||||
);
|
||||
return (true, '');
|
||||
} else {
|
||||
return (true, selectionText);
|
||||
}
|
||||
}
|
||||
|
||||
@ -360,19 +336,9 @@ class AiWriterCubit extends Cubit<AiWriterState> {
|
||||
sourceIds: selectedSourcesNotifier.value,
|
||||
completionType: command.toCompletionType(),
|
||||
onStart: () async {
|
||||
final transaction = editorState.transaction;
|
||||
final position = ensurePreviousNodeIsEmptyParagraph(
|
||||
final position = await ensurePreviousNodeIsEmptyParagraph(
|
||||
editorState,
|
||||
aiWriterNode!,
|
||||
transaction,
|
||||
);
|
||||
await editorState.apply(
|
||||
transaction,
|
||||
options: ApplyOptions(
|
||||
inMemoryUpdate: true,
|
||||
recordUndo: false,
|
||||
),
|
||||
withUpdateSelection: false,
|
||||
);
|
||||
_textRobot.start(position: position);
|
||||
records.add(
|
||||
@ -461,20 +427,9 @@ class AiWriterCubit extends Cubit<AiWriterState> {
|
||||
sourceIds: selectedSourcesNotifier.value,
|
||||
format: predefinedFormat,
|
||||
onStart: () async {
|
||||
final transaction = editorState.transaction;
|
||||
final position = ensurePreviousNodeIsEmptyParagraph(
|
||||
final position = await ensurePreviousNodeIsEmptyParagraph(
|
||||
editorState,
|
||||
aiWriterNode!,
|
||||
transaction,
|
||||
);
|
||||
transaction.afterSelection = null;
|
||||
await editorState.apply(
|
||||
transaction,
|
||||
options: ApplyOptions(
|
||||
inMemoryUpdate: true,
|
||||
recordUndo: false,
|
||||
),
|
||||
withUpdateSelection: false,
|
||||
);
|
||||
_textRobot.start(position: position);
|
||||
records.add(
|
||||
@ -555,26 +510,14 @@ class AiWriterCubit extends Cubit<AiWriterState> {
|
||||
history: records,
|
||||
sourceIds: selectedSourcesNotifier.value,
|
||||
onStart: () async {
|
||||
final transaction = editorState.transaction;
|
||||
formatSelection(
|
||||
await formatSelection(
|
||||
editorState,
|
||||
selection,
|
||||
transaction,
|
||||
ApplySuggestionFormatType.original,
|
||||
);
|
||||
final position = ensurePreviousNodeIsEmptyParagraph(
|
||||
final position = await ensurePreviousNodeIsEmptyParagraph(
|
||||
editorState,
|
||||
aiWriterNode!,
|
||||
transaction,
|
||||
);
|
||||
transaction.afterSelection = null;
|
||||
await editorState.apply(
|
||||
transaction,
|
||||
options: ApplyOptions(
|
||||
inMemoryUpdate: true,
|
||||
recordUndo: false,
|
||||
),
|
||||
withUpdateSelection: false,
|
||||
);
|
||||
_textRobot.start(position: position);
|
||||
records.add(
|
||||
|
||||
@ -198,9 +198,11 @@ class _AiWriterScrollWrapperState extends State<AiWriterScrollWrapper> {
|
||||
throttler.call(() {
|
||||
if (aiWriterCubit.aiWriterNode != null) {
|
||||
final path = aiWriterCubit.aiWriterNode!.path;
|
||||
widget.editorState.updateSelectionWithReason(
|
||||
Selection.collapsed(Position(path: path)),
|
||||
);
|
||||
if (path.isNotEmpty) {
|
||||
widget.editorState.updateSelectionWithReason(
|
||||
Selection.collapsed(Position(path: path)),
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@ -58,7 +58,7 @@ class MarkdownTextRobot {
|
||||
void start({
|
||||
Position? position,
|
||||
}) {
|
||||
_insertPosition ??= position ?? editorState.selection?.start;
|
||||
_insertPosition = position ?? editorState.selection?.start;
|
||||
|
||||
if (_enableDebug) {
|
||||
Log.info(
|
||||
@ -148,11 +148,15 @@ class MarkdownTextRobot {
|
||||
}
|
||||
}
|
||||
|
||||
void reset() {
|
||||
void clear() {
|
||||
_markdownText = '';
|
||||
_insertedNodes = [];
|
||||
}
|
||||
|
||||
void reset() {
|
||||
_insertPosition = null;
|
||||
}
|
||||
|
||||
Future<void> _refresh({
|
||||
required bool inMemoryUpdate,
|
||||
bool updateSelection = false,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user