mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2025-12-28 07:33:45 +00:00
fix: numbered list generated by ai should keep the same index as the input (#7622)
Co-authored-by: Richard Shiue <71320345+richardshiue@users.noreply.github.com>
This commit is contained in:
parent
24bb1b58a0
commit
9115e208ac
@ -519,7 +519,7 @@ class AiWriterCubit extends Cubit<AiWriterState> {
|
||||
editorState,
|
||||
aiWriterNode!,
|
||||
);
|
||||
_textRobot.start(position: position);
|
||||
_textRobot.start(position: position, previousSelection: selection);
|
||||
records.add(
|
||||
AiWriterRecord.user(
|
||||
content: prompt,
|
||||
|
||||
@ -1,8 +1,10 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:appflowy/plugins/document/presentation/editor_plugins/numbered_list/numbered_list_icon.dart';
|
||||
import 'package:appflowy/shared/markdown_to_document.dart';
|
||||
import 'package:appflowy_backend/log.dart';
|
||||
import 'package:appflowy_editor/appflowy_editor.dart';
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:synchronized/synchronized.dart';
|
||||
|
||||
const _enableDebug = false;
|
||||
@ -28,6 +30,9 @@ class MarkdownTextRobot {
|
||||
/// Only for debug via [_enableDebug].
|
||||
final List<String> _debugMarkdownTexts = [];
|
||||
|
||||
/// Selection before the refresh.
|
||||
Selection? _previousSelection;
|
||||
|
||||
bool get hasAnyResult => _markdownText.isNotEmpty;
|
||||
|
||||
String get markdownText => _markdownText;
|
||||
@ -56,9 +61,11 @@ class MarkdownTextRobot {
|
||||
}
|
||||
|
||||
void start({
|
||||
Selection? previousSelection,
|
||||
Position? position,
|
||||
}) {
|
||||
_insertPosition = position ?? editorState.selection?.start;
|
||||
_previousSelection = previousSelection ?? editorState.selection;
|
||||
|
||||
if (_enableDebug) {
|
||||
Log.info(
|
||||
@ -175,11 +182,40 @@ class MarkdownTextRobot {
|
||||
tableWidth: 250.0,
|
||||
).root.children;
|
||||
|
||||
// check if the first selected node before the refresh is a numbered list node
|
||||
final previousSelection = _previousSelection;
|
||||
final previousSelectedNode = previousSelection == null
|
||||
? null
|
||||
: editorState.getNodeAtPath(previousSelection.start.path);
|
||||
final firstNodeIsNumberedList = previousSelectedNode != null &&
|
||||
previousSelectedNode.type == NumberedListBlockKeys.type;
|
||||
|
||||
final newNodes = attributes == null
|
||||
? documentNodes
|
||||
: documentNodes
|
||||
.map((node) => _styleDelta(node: node, attributes: attributes))
|
||||
.toList();
|
||||
: documentNodes.mapIndexed((index, node) {
|
||||
final n = _styleDelta(node: node, attributes: attributes);
|
||||
n.externalValues = AINodeExternalValues(
|
||||
isAINode: true,
|
||||
);
|
||||
if (index == 0 && n.type == NumberedListBlockKeys.type) {
|
||||
if (firstNodeIsNumberedList) {
|
||||
final builder = NumberedListIndexBuilder(
|
||||
editorState: editorState,
|
||||
node: previousSelectedNode,
|
||||
);
|
||||
final firstIndex = builder.indexInSameLevel;
|
||||
n.updateAttributes({
|
||||
NumberedListBlockKeys.number: firstIndex,
|
||||
});
|
||||
}
|
||||
|
||||
n.externalValues = AINodeExternalValues(
|
||||
isAINode: true,
|
||||
isFirstNumberedListNode: true,
|
||||
);
|
||||
}
|
||||
return n;
|
||||
}).toList();
|
||||
|
||||
if (newNodes.isEmpty) {
|
||||
return;
|
||||
@ -247,3 +283,13 @@ class MarkdownTextRobot {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class AINodeExternalValues extends NodeExternalValues {
|
||||
const AINodeExternalValues({
|
||||
this.isAINode = false,
|
||||
this.isFirstNumberedListNode = false,
|
||||
});
|
||||
|
||||
final bool isAINode;
|
||||
final bool isFirstNumberedListNode;
|
||||
}
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import 'package:appflowy/plugins/document/presentation/editor_plugins/base/markdown_text_robot.dart';
|
||||
import 'package:appflowy_editor/appflowy_editor.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
@ -31,7 +32,7 @@ class NumberedListIcon extends StatelessWidget {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(left: 6.0, right: 10.0),
|
||||
child: Text(
|
||||
node.levelString,
|
||||
node.buildLevelString(context),
|
||||
style: adjustedTextStyle,
|
||||
strutStyle: StrutStyle.fromTextStyle(combinedTextStyle),
|
||||
textHeightBehavior: TextHeightBehavior(
|
||||
@ -47,9 +48,12 @@ class NumberedListIcon extends StatelessWidget {
|
||||
}
|
||||
}
|
||||
|
||||
extension on Node {
|
||||
String get levelString {
|
||||
final builder = _NumberedListIconBuilder(node: this);
|
||||
extension NumberedListNodeIndex on Node {
|
||||
String buildLevelString(BuildContext context) {
|
||||
final builder = NumberedListIndexBuilder(
|
||||
editorState: context.read<EditorState>(),
|
||||
node: this,
|
||||
);
|
||||
final indexInRootLevel = builder.indexInRootLevel;
|
||||
final indexInSameLevel = builder.indexInSameLevel;
|
||||
final level = indexInRootLevel % 3;
|
||||
@ -62,11 +66,13 @@ extension on Node {
|
||||
}
|
||||
}
|
||||
|
||||
class _NumberedListIconBuilder {
|
||||
_NumberedListIconBuilder({
|
||||
class NumberedListIndexBuilder {
|
||||
NumberedListIndexBuilder({
|
||||
required this.editorState,
|
||||
required this.node,
|
||||
});
|
||||
|
||||
final EditorState editorState;
|
||||
final Node node;
|
||||
|
||||
// the level of the current node
|
||||
@ -88,7 +94,13 @@ class _NumberedListIconBuilder {
|
||||
Node? previous = node.previous;
|
||||
|
||||
// if the previous one is not a numbered list, then it is the first one
|
||||
if (previous == null || previous.type != NumberedListBlockKeys.type) {
|
||||
final aiNodeExternalValues =
|
||||
node.externalValues?.unwrapOrNull<AINodeExternalValues>();
|
||||
|
||||
if (previous == null ||
|
||||
previous.type != NumberedListBlockKeys.type ||
|
||||
(aiNodeExternalValues != null &&
|
||||
aiNodeExternalValues.isFirstNumberedListNode)) {
|
||||
return node.attributes[NumberedListBlockKeys.number] ?? level;
|
||||
}
|
||||
|
||||
@ -97,10 +109,17 @@ class _NumberedListIconBuilder {
|
||||
startNumber = previous.attributes[NumberedListBlockKeys.number] as int?;
|
||||
level++;
|
||||
previous = previous.previous;
|
||||
|
||||
// break the loop if the start number is found when the current node is an AI node
|
||||
if (aiNodeExternalValues != null && startNumber != null) {
|
||||
return startNumber + level - 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (startNumber != null) {
|
||||
return startNumber + level - 1;
|
||||
level = startNumber + level - 1;
|
||||
}
|
||||
|
||||
return level;
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user