fix: ai writer issues (#7467)

* fix: disable ai writer in table

* fix: enable header row by default when converting from md

* chore: add title when continue writing

* chore: rewrite using predefined format

* fix: mouse & keyboard event still propagate

* chore: bump editor ref
This commit is contained in:
Richard Shiue 2025-03-06 15:09:33 +08:00 committed by GitHub
parent f8c18afbcf
commit 884586f0af
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 63 additions and 37 deletions

View File

@ -81,8 +81,8 @@ class _AppFlowyEditorPageState extends State<AppFlowyEditorPage>
];
final List<ToolbarItem> toolbarItems = [
improveWritingItem..isActive = onlyShowInTextType,
aiWriterItem..isActive = onlyShowInTextType,
improveWritingItem..isActive = onlyShowInTextTypeAndExcludeTable,
aiWriterItem..isActive = onlyShowInTextTypeAndExcludeTable,
paragraphItem..isActive = onlyShowInSingleTextTypeSelectionAndExcludeTable,
headingsToolbarItem
..isActive = onlyShowInSingleTextTypeSelectionAndExcludeTable,

View File

@ -163,11 +163,8 @@ class _AIWriterBlockComponentState extends State<AiWriterBlockComponent> {
children: [
BlocBuilder<AiWriterCubit, AiWriterState>(
builder: (context, state) {
final hitTestBehavior = state is GeneratingAiWriterState
? HitTestBehavior.opaque
: HitTestBehavior.translucent;
return GestureDetector(
behavior: hitTestBehavior,
behavior: HitTestBehavior.opaque,
onTap: () => onTapOutside(),
onTapDown: (_) => onTapOutside(),
);
@ -280,7 +277,7 @@ class OverlayContent extends StatelessWidget {
hasSelection: hasSelection,
),
onTap: (action) {
context.read<AiWriterCubit>().runResponseAction(action);
_onSelectSuggestionAction(context, action);
},
),
),
@ -346,9 +343,7 @@ class OverlayContent extends StatelessWidget {
hasSelection: hasSelection,
),
onTap: (action) {
context
.read<AiWriterCubit>()
.runResponseAction(action);
_onSelectSuggestionAction(context, action);
},
),
],
@ -539,6 +534,18 @@ class OverlayContent extends StatelessWidget {
};
}
}
void _onSelectSuggestionAction(
BuildContext context,
SuggestionAction action,
) {
final predefinedFormat =
context.read<AIPromptInputBloc>().state.predefinedFormat;
context.read<AiWriterCubit>().runResponseAction(
action,
predefinedFormat,
);
}
}
class MainContentArea extends StatelessWidget {

View File

@ -1,6 +1,7 @@
import 'package:appflowy/generated/flowy_svgs.g.dart';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/plugins/document/application/document_bloc.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/plugins.dart';
import 'package:appflowy/workspace/presentation/widgets/dialogs.dart';
import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:easy_localization/easy_localization.dart';
@ -8,7 +9,6 @@ import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'ai_writer_block_component.dart';
import 'operations/ai_writer_entities.dart';
const _improveWritingToolbarItemId = 'appflowy.editor.ai_improve_writing';
@ -223,7 +223,6 @@ void _insertAiNode(EditorState editorState, AiWriterCommand command) async {
command: command,
),
)
..afterSelection = selection
..selectionExtraInfo = {selectionExtraInfoDisableToolbar: true};
await editorState.apply(
@ -232,6 +231,7 @@ void _insertAiNode(EditorState editorState, AiWriterCommand command) async {
recordUndo: false,
inMemoryUpdate: true,
),
withUpdateSelection: false,
);
}
@ -240,3 +240,9 @@ bool _isAIEnabled(EditorState editorState) {
return documentContext == null ||
!documentContext.read<DocumentBloc>().isLocalMode;
}
bool onlyShowInTextTypeAndExcludeTable(
EditorState editorState,
) {
return onlyShowInTextType(editorState) && notShowInTable(editorState);
}

View File

@ -2,9 +2,11 @@ import 'dart:async';
import 'package:appflowy/ai/ai.dart';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/workspace/application/view/view_service.dart';
import 'package:appflowy_backend/dispatch/dispatch.dart';
import 'package:appflowy_backend/protobuf/flowy-ai/protobuf.dart';
import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:appflowy_result/appflowy_result.dart';
import 'package:bloc/bloc.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/foundation.dart';
@ -30,7 +32,7 @@ class AiWriterCubit extends Cubit<AiWriterState> {
isFirstRun: true,
),
) {
editorState.service.keyboardService?.disable();
editorState.service.keyboardService?.disableShortcuts();
}
final String documentId;
@ -47,7 +49,7 @@ class AiWriterCubit extends Cubit<AiWriterState> {
@override
Future<void> close() async {
selectedSourcesNotifier.dispose();
editorState.service.keyboardService?.enable();
editorState.service.keyboardService?.enableShortcuts();
await super.close();
}
@ -184,11 +186,14 @@ class AiWriterCubit extends Cubit<AiWriterState> {
await removeAiWriterNode(editorState, getAiWriterNode());
}
void runResponseAction(SuggestionAction action) async {
void runResponseAction(
SuggestionAction action, [
PredefinedFormat? predefinedFormat,
]) async {
if (action case SuggestionAction.rewrite || SuggestionAction.tryAgain) {
await _textRobot.discard();
_textRobot.reset();
runCommand(state.command, null, isRetry: true);
runCommand(state.command, predefinedFormat, isRetry: true);
return;
}
@ -295,32 +300,39 @@ class AiWriterCubit extends Cubit<AiWriterState> {
end: cursorPosition,
).normalized;
final text = await editorState.getMarkdownInSelection(selection);
String text = await editorState.getMarkdownInSelection(selection);
if (text.isEmpty) {
if (state is! ReadyAiWriterState) {
return;
}
final readyState = state as ReadyAiWriterState;
emit(
SingleShotAiWriterState(
command,
title: LocaleKeys.ai_continueWritingEmptyDocumentTitle.tr(),
description:
LocaleKeys.ai_continueWritingEmptyDocumentDescription.tr(),
onDismiss: () {
if (isImmediateRun) {
removeAiWriterNode(editorState, node);
}
},
),
);
emit(readyState);
return;
final view = await ViewBackendService.getView(documentId).toNullable();
if (view == null ||
view.name.isEmpty ||
view.name == LocaleKeys.menuAppHeader_defaultNewPageName.tr()) {
final readyState = state as ReadyAiWriterState;
emit(
SingleShotAiWriterState(
command,
title: LocaleKeys.ai_continueWritingEmptyDocumentTitle.tr(),
description:
LocaleKeys.ai_continueWritingEmptyDocumentDescription.tr(),
onDismiss: () {
if (isImmediateRun) {
removeAiWriterNode(editorState, node);
}
},
),
);
emit(readyState);
return;
} else {
text += view.name;
}
}
final stream = await _aiService.streamCompletion(
objectId: documentId,
text: await editorState.getMarkdownInSelection(selection),
text: text,
completionType: command.toCompletionType(),
onStart: () async {
final transaction = editorState.transaction;

View File

@ -106,6 +106,7 @@ class MarkdownSimpleTableParser extends CustomMarkdownParser {
return [
simpleTableBlockNode(
children: rows,
enableHeaderRow: true,
columnWidths: UniversalPlatform.isMobile || tableWidth == null
? null
: {for (var i = 0; i < th.length; i++) i.toString(): tableWidth!},

View File

@ -90,8 +90,8 @@ packages:
dependency: "direct main"
description:
path: "."
ref: b2672f2
resolved-ref: b2672f297b0e9e7a028ea217ae6a57c8dca3da4e
ref: "866aea4"
resolved-ref: "866aea4daca836d5734df4fca20563338755e82a"
url: "https://github.com/AppFlowy-IO/appflowy-editor.git"
source: git
version: "5.1.0"

View File

@ -180,7 +180,7 @@ dependency_overrides:
appflowy_editor:
git:
url: https://github.com/AppFlowy-IO/appflowy-editor.git
ref: "b2672f2"
ref: "866aea4"
appflowy_editor_plugins:
git: