Skip to content

Commit 7ff4cec

Browse files
authored
feat: add cover migration for document (#1929)
* feat: add cover migration for document * fix: should not delete the cover when selecting all * fix: chinese characters for openai
1 parent 675c833 commit 7ff4cec

File tree

4 files changed

+81
-35
lines changed

4 files changed

+81
-35
lines changed

frontend/appflowy_flutter/lib/plugins/document/application/doc_bloc.dart

Lines changed: 62 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,18 @@
11
import 'dart:convert';
2+
import 'package:appflowy/plugins/document/presentation/plugins/cover/cover_node_widget.dart';
23
import 'package:appflowy/plugins/trash/application/trash_service.dart';
34
import 'package:appflowy/user/application/user_service.dart';
45
import 'package:appflowy/workspace/application/view/view_listener.dart';
56
import 'package:appflowy/plugins/document/application/doc_service.dart';
7+
import 'package:appflowy_backend/protobuf/flowy-document/entities.pb.dart';
68
import 'package:appflowy_backend/protobuf/flowy-user/user_profile.pbserver.dart';
79
import 'package:appflowy_editor/appflowy_editor.dart'
8-
show EditorState, Document, Transaction;
10+
show EditorState, Document, Transaction, Node;
911
import 'package:appflowy_backend/protobuf/flowy-folder/trash.pb.dart';
1012
import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
1113
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
1214
import 'package:appflowy_backend/log.dart';
15+
import 'package:flutter/foundation.dart';
1316
import 'package:flutter_bloc/flutter_bloc.dart';
1417
import 'package:freezed_annotation/freezed_annotation.dart';
1518
import 'package:dartz/dartz.dart';
@@ -78,29 +81,27 @@ class DocumentBloc extends Bloc<DocumentEvent, DocumentState> {
7881
Future<void> _initial(Initial value, Emitter<DocumentState> emit) async {
7982
final userProfile = await UserBackendService.getCurrentUserProfile();
8083
if (userProfile.isRight()) {
81-
emit(
84+
return emit(
8285
state.copyWith(
8386
loadingState: DocumentLoadingState.finish(
8487
right(userProfile.asRight()),
8588
),
8689
),
8790
);
88-
return;
8991
}
9092
final result = await _documentService.openDocument(view: view);
91-
result.fold(
92-
(documentData) {
93-
final document = Document.fromJson(jsonDecode(documentData.content));
94-
editorState = EditorState(document: document);
95-
_listenOnDocumentChange();
96-
emit(
97-
state.copyWith(
98-
loadingState: DocumentLoadingState.finish(left(unit)),
99-
userProfilePB: userProfile.asLeft(),
100-
),
101-
);
93+
return result.fold(
94+
(documentData) async {
95+
await _initEditorState(documentData).whenComplete(() {
96+
emit(
97+
state.copyWith(
98+
loadingState: DocumentLoadingState.finish(left(unit)),
99+
userProfilePB: userProfile.asLeft(),
100+
),
101+
);
102+
});
102103
},
103-
(err) {
104+
(err) async {
104105
emit(
105106
state.copyWith(
106107
loadingState: DocumentLoadingState.finish(right(err)),
@@ -127,8 +128,13 @@ class DocumentBloc extends Bloc<DocumentEvent, DocumentState> {
127128
);
128129
}
129130

130-
void _listenOnDocumentChange() {
131-
_subscription = editorState?.transactionStream.listen((transaction) {
131+
Future<void> _initEditorState(DocumentDataPB documentData) async {
132+
final document = Document.fromJson(jsonDecode(documentData.content));
133+
final editorState = EditorState(document: document);
134+
this.editorState = editorState;
135+
136+
// listen on document change
137+
_subscription = editorState.transactionStream.listen((transaction) {
132138
final json = jsonEncode(TransactionAdaptor(transaction).toJson());
133139
_documentService
134140
.applyEdit(docId: view.id, operations: json)
@@ -139,6 +145,15 @@ class DocumentBloc extends Bloc<DocumentEvent, DocumentState> {
139145
);
140146
});
141147
});
148+
// log
149+
if (kDebugMode) {
150+
editorState.logConfiguration.handler = (log) {
151+
Log.debug(log);
152+
};
153+
}
154+
// migration
155+
final migration = DocumentMigration(editorState: editorState);
156+
await migration.apply();
142157
}
143158
}
144159

@@ -215,3 +230,33 @@ class TransactionAdaptor {
215230
return json;
216231
}
217232
}
233+
234+
class DocumentMigration {
235+
const DocumentMigration({
236+
required this.editorState,
237+
});
238+
239+
final EditorState editorState;
240+
241+
/// Migrate the document to the latest version.
242+
Future<void> apply() async {
243+
final transaction = editorState.transaction;
244+
245+
// A temporary solution to migrate the document to the latest version.
246+
// Once the editor is stable, we can remove this.
247+
248+
// cover plugin
249+
if (editorState.document.nodeAtPath([0])?.type != kCoverType) {
250+
transaction.insertNode(
251+
[0],
252+
Node(type: kCoverType),
253+
);
254+
}
255+
256+
transaction.afterSelection = null;
257+
258+
if (transaction.operations.isNotEmpty) {
259+
editorState.apply(transaction);
260+
}
261+
}
262+
}

frontend/appflowy_flutter/lib/plugins/document/presentation/plugins/openai/service/openai_client.dart

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,13 @@ class HttpOpenAIRepository implements OpenAIRepository {
9191
);
9292

9393
if (response.statusCode == 200) {
94-
return Right(TextCompletionResponse.fromJson(json.decode(response.body)));
94+
return Right(
95+
TextCompletionResponse.fromJson(
96+
json.decode(
97+
utf8.decode(response.bodyBytes),
98+
),
99+
),
100+
);
95101
} else {
96102
return Left(OpenAIError.fromJson(json.decode(response.body)['error']));
97103
}
@@ -119,7 +125,13 @@ class HttpOpenAIRepository implements OpenAIRepository {
119125
);
120126

121127
if (response.statusCode == 200) {
122-
return Right(TextEditResponse.fromJson(json.decode(response.body)));
128+
return Right(
129+
TextEditResponse.fromJson(
130+
json.decode(
131+
utf8.decode(response.bodyBytes),
132+
),
133+
),
134+
);
123135
} else {
124136
return Left(OpenAIError.fromJson(json.decode(response.body)['error']));
125137
}

frontend/appflowy_flutter/lib/workspace/presentation/home/menu/app/header/add_button.dart

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
import 'package:appflowy/plugins/document/document.dart';
2-
import 'package:appflowy/plugins/document/presentation/plugins/cover/cover_node_widget.dart';
32
import 'package:appflowy/startup/plugin/plugin.dart';
43
import 'package:appflowy/startup/startup.dart';
54
import 'package:appflowy/workspace/presentation/home/menu/app/header/import/import_panel.dart';
65
import 'package:appflowy/workspace/presentation/widgets/pop_up_action.dart';
7-
import 'package:appflowy_editor/appflowy_editor.dart' show Document, Node;
6+
import 'package:appflowy_editor/appflowy_editor.dart' show Document;
87
import 'package:appflowy_popover/appflowy_popover.dart';
98
import 'package:flowy_infra/image.dart';
109
import 'package:flowy_infra_ui/style_widget/icon_button.dart';
@@ -61,12 +60,7 @@ class AddButton extends StatelessWidget {
6160
},
6261
onSelected: (action, controller) {
6362
if (action is AddButtonActionWrapper) {
64-
Document? document;
65-
if (action.pluginType == PluginType.editor) {
66-
// initialize the document if needed.
67-
document = buildInitialDocument();
68-
}
69-
onSelected(action.pluginBuilder, document);
63+
onSelected(action.pluginBuilder, null);
7064
}
7165
if (action is ImportActionWrapper) {
7266
showImportPanel(context, (document) {
@@ -80,12 +74,6 @@ class AddButton extends StatelessWidget {
8074
},
8175
);
8276
}
83-
84-
Document buildInitialDocument() {
85-
final document = Document.empty();
86-
document.insert([0], [Node(type: kCoverType)]);
87-
return document;
88-
}
8977
}
9078

9179
class AddButtonActionWrapper extends ActionCell {

frontend/appflowy_flutter/packages/appflowy_editor/lib/src/service/internal_key_event_handlers/backspace_handler.dart

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,9 @@ ShortcutEventHandler backspaceEventHandler = (editorState, event) {
1212
nodes = selection.isBackward ? nodes : nodes.reversed.toList(growable: false);
1313
selection = selection.isBackward ? selection : selection.reversed;
1414
final textNodes = nodes.whereType<TextNode>().toList();
15-
final List<Node> nonTextNodes =
16-
nodes.where((node) => node is! TextNode).toList(growable: false);
15+
final List<Node> nonTextNodes = nodes
16+
.where((node) => node is! TextNode && node.selectable != null)
17+
.toList(growable: false);
1718

1819
final transaction = editorState.transaction;
1920
List<int>? cancelNumberListPath;

0 commit comments

Comments
 (0)