468 lines
15 KiB
Dart
Raw Normal View History

2023-08-17 14:50:48 +08:00
import 'dart:async';
import 'dart:convert';
2023-08-17 14:50:48 +08:00
import 'package:appflowy/plugins/document/application/doc_sync_state_listener.dart';
import 'package:appflowy/plugins/document/application/document_awareness_metadata.dart';
import 'package:appflowy/plugins/document/application/document_collab_adapter.dart';
feat: integrate new editor (#2536) * feat: update editor * feat: integrate new editor * feat: integrate the document2 into folder2 * feat: integrate the new editor * chore: cargo fix * chore: active document feature for flowy-error * feat: convert the editor action to collab action * feat: migrate the grid and board * feat: migrate the callout block * feat: migrate the divider * chore: migrate the callout and math equation * feat: migrate the code block * feat: add shift + enter command in code block * feat: support tab and shift+tab in code block * fix: cursor error after inserting divider * feat: migrate the grid and board * feat: migrate the emoji picker * feat: migrate openai * feat: integrate floating toolbar * feat: migrate the smart editor * feat: migrate the cover * feat: add option block action * chore: implement block selection and delete option * feat: support background color * feat: dismiss color picker afer setting color * feat: migrate the cover block * feat: resize the font * chore: cutomsize the padding * chore: wrap the option button with ignore widget * feat: customize the heading style * chore: optimize the divider line height * fix: the option button can't dismiss * ci: rust test * chore: flutter analyze * fix: code block selection * fix: dismiss the emoji picker after selecting one * chore: optimize the transaction adapter * fix: can't save the new content * feat: show export page when some errors happen * feat: implement get_view_data for document --------- Co-authored-by: nathan <nathan@appflowy.io>
2023-05-16 14:58:24 +08:00
import 'package:appflowy/plugins/document/application/document_data_pb_extension.dart';
import 'package:appflowy/plugins/document/application/document_listener.dart';
import 'package:appflowy/plugins/document/application/document_service.dart';
feat: integrate new editor (#2536) * feat: update editor * feat: integrate new editor * feat: integrate the document2 into folder2 * feat: integrate the new editor * chore: cargo fix * chore: active document feature for flowy-error * feat: convert the editor action to collab action * feat: migrate the grid and board * feat: migrate the callout block * feat: migrate the divider * chore: migrate the callout and math equation * feat: migrate the code block * feat: add shift + enter command in code block * feat: support tab and shift+tab in code block * fix: cursor error after inserting divider * feat: migrate the grid and board * feat: migrate the emoji picker * feat: migrate openai * feat: integrate floating toolbar * feat: migrate the smart editor * feat: migrate the cover * feat: add option block action * chore: implement block selection and delete option * feat: support background color * feat: dismiss color picker afer setting color * feat: migrate the cover block * feat: resize the font * chore: cutomsize the padding * chore: wrap the option button with ignore widget * feat: customize the heading style * chore: optimize the divider line height * fix: the option button can't dismiss * ci: rust test * chore: flutter analyze * fix: code block selection * fix: dismiss the emoji picker after selecting one * chore: optimize the transaction adapter * fix: can't save the new content * feat: show export page when some errors happen * feat: implement get_view_data for document --------- Co-authored-by: nathan <nathan@appflowy.io>
2023-05-16 14:58:24 +08:00
import 'package:appflowy/plugins/document/application/editor_transaction_adapter.dart';
import 'package:appflowy/plugins/trash/application/trash_service.dart';
import 'package:appflowy/shared/feature_flags.dart';
import 'package:appflowy/startup/startup.dart';
import 'package:appflowy/startup/tasks/device_info_task.dart';
import 'package:appflowy/user/application/auth/auth_service.dart';
import 'package:appflowy/util/color_generator/color_generator.dart';
import 'package:appflowy/util/color_to_hex_string.dart';
import 'package:appflowy/util/debounce.dart';
2024-04-08 14:06:05 +08:00
import 'package:appflowy/util/throttle.dart';
2023-08-17 14:50:48 +08:00
import 'package:appflowy/workspace/application/view/view_listener.dart';
import 'package:appflowy_backend/log.dart';
import 'package:appflowy_backend/protobuf/flowy-document/entities.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-document/protobuf.dart';
import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-user/protobuf.dart';
2023-08-17 14:50:48 +08:00
import 'package:appflowy_editor/appflowy_editor.dart'
show
EditorState,
AppFlowyEditorLogLevel,
2023-08-17 14:50:48 +08:00
TransactionTime,
Selection,
Position,
paragraphNode;
import 'package:appflowy_result/appflowy_result.dart';
import 'package:flutter/foundation.dart';
2021-09-11 21:30:58 +08:00
import 'package:flutter_bloc/flutter_bloc.dart';
2021-07-24 18:55:13 +08:00
import 'package:freezed_annotation/freezed_annotation.dart';
2023-08-17 14:50:48 +08:00
part 'document_bloc.freezed.dart';
2021-07-24 18:55:13 +08:00
bool enableDocumentInternalLog = false;
2022-02-23 22:17:47 +08:00
class DocumentBloc extends Bloc<DocumentEvent, DocumentState> {
DocumentBloc({
required this.documentId,
this.databaseViewId,
this.rowId,
}) : _documentListener = DocumentListener(id: documentId),
_syncStateListener = DocumentSyncStateListener(id: documentId),
2022-10-26 10:38:57 +08:00
super(DocumentState.initial()) {
_viewListener = databaseViewId == null && rowId == null
? ViewListener(viewId: documentId)
: null;
feat: integrate new editor (#2536) * feat: update editor * feat: integrate new editor * feat: integrate the document2 into folder2 * feat: integrate the new editor * chore: cargo fix * chore: active document feature for flowy-error * feat: convert the editor action to collab action * feat: migrate the grid and board * feat: migrate the callout block * feat: migrate the divider * chore: migrate the callout and math equation * feat: migrate the code block * feat: add shift + enter command in code block * feat: support tab and shift+tab in code block * fix: cursor error after inserting divider * feat: migrate the grid and board * feat: migrate the emoji picker * feat: migrate openai * feat: integrate floating toolbar * feat: migrate the smart editor * feat: migrate the cover * feat: add option block action * chore: implement block selection and delete option * feat: support background color * feat: dismiss color picker afer setting color * feat: migrate the cover block * feat: resize the font * chore: cutomsize the padding * chore: wrap the option button with ignore widget * feat: customize the heading style * chore: optimize the divider line height * fix: the option button can't dismiss * ci: rust test * chore: flutter analyze * fix: code block selection * fix: dismiss the emoji picker after selecting one * chore: optimize the transaction adapter * fix: can't save the new content * feat: show export page when some errors happen * feat: implement get_view_data for document --------- Co-authored-by: nathan <nathan@appflowy.io>
2023-05-16 14:58:24 +08:00
on<DocumentEvent>(_onDocumentEvent);
2021-07-24 18:55:13 +08:00
}
2021-09-11 21:30:58 +08:00
/// For a normal document, the document id is the same as the view id
final String documentId;
final String? databaseViewId;
final String? rowId;
feat: integrate new editor (#2536) * feat: update editor * feat: integrate new editor * feat: integrate the document2 into folder2 * feat: integrate the new editor * chore: cargo fix * chore: active document feature for flowy-error * feat: convert the editor action to collab action * feat: migrate the grid and board * feat: migrate the callout block * feat: migrate the divider * chore: migrate the callout and math equation * feat: migrate the code block * feat: add shift + enter command in code block * feat: support tab and shift+tab in code block * fix: cursor error after inserting divider * feat: migrate the grid and board * feat: migrate the emoji picker * feat: migrate openai * feat: integrate floating toolbar * feat: migrate the smart editor * feat: migrate the cover * feat: add option block action * chore: implement block selection and delete option * feat: support background color * feat: dismiss color picker afer setting color * feat: migrate the cover block * feat: resize the font * chore: cutomsize the padding * chore: wrap the option button with ignore widget * feat: customize the heading style * chore: optimize the divider line height * fix: the option button can't dismiss * ci: rust test * chore: flutter analyze * fix: code block selection * fix: dismiss the emoji picker after selecting one * chore: optimize the transaction adapter * fix: can't save the new content * feat: show export page when some errors happen * feat: implement get_view_data for document --------- Co-authored-by: nathan <nathan@appflowy.io>
2023-05-16 14:58:24 +08:00
final DocumentListener _documentListener;
final DocumentSyncStateListener _syncStateListener;
late final ViewListener? _viewListener;
2021-11-03 23:03:42 +08:00
final DocumentService _documentService = DocumentService();
final TrashService _trashService = TrashService();
feat: integrate new editor (#2536) * feat: update editor * feat: integrate new editor * feat: integrate the document2 into folder2 * feat: integrate the new editor * chore: cargo fix * chore: active document feature for flowy-error * feat: convert the editor action to collab action * feat: migrate the grid and board * feat: migrate the callout block * feat: migrate the divider * chore: migrate the callout and math equation * feat: migrate the code block * feat: add shift + enter command in code block * feat: support tab and shift+tab in code block * fix: cursor error after inserting divider * feat: migrate the grid and board * feat: migrate the emoji picker * feat: migrate openai * feat: integrate floating toolbar * feat: migrate the smart editor * feat: migrate the cover * feat: add option block action * chore: implement block selection and delete option * feat: support background color * feat: dismiss color picker afer setting color * feat: migrate the cover block * feat: resize the font * chore: cutomsize the padding * chore: wrap the option button with ignore widget * feat: customize the heading style * chore: optimize the divider line height * fix: the option button can't dismiss * ci: rust test * chore: flutter analyze * fix: code block selection * fix: dismiss the emoji picker after selecting one * chore: optimize the transaction adapter * fix: can't save the new content * feat: show export page when some errors happen * feat: implement get_view_data for document --------- Co-authored-by: nathan <nathan@appflowy.io>
2023-05-16 14:58:24 +08:00
late DocumentCollabAdapter _documentCollabAdapter;
late final TransactionAdapter _transactionAdapter = TransactionAdapter(
documentId: documentId,
documentService: _documentService,
);
feat: integrate new editor (#2536) * feat: update editor * feat: integrate new editor * feat: integrate the document2 into folder2 * feat: integrate the new editor * chore: cargo fix * chore: active document feature for flowy-error * feat: convert the editor action to collab action * feat: migrate the grid and board * feat: migrate the callout block * feat: migrate the divider * chore: migrate the callout and math equation * feat: migrate the code block * feat: add shift + enter command in code block * feat: support tab and shift+tab in code block * fix: cursor error after inserting divider * feat: migrate the grid and board * feat: migrate the emoji picker * feat: migrate openai * feat: integrate floating toolbar * feat: migrate the smart editor * feat: migrate the cover * feat: add option block action * chore: implement block selection and delete option * feat: support background color * feat: dismiss color picker afer setting color * feat: migrate the cover block * feat: resize the font * chore: cutomsize the padding * chore: wrap the option button with ignore widget * feat: customize the heading style * chore: optimize the divider line height * fix: the option button can't dismiss * ci: rust test * chore: flutter analyze * fix: code block selection * fix: dismiss the emoji picker after selecting one * chore: optimize the transaction adapter * fix: can't save the new content * feat: show export page when some errors happen * feat: implement get_view_data for document --------- Co-authored-by: nathan <nathan@appflowy.io>
2023-05-16 14:58:24 +08:00
StreamSubscription? _transactionSubscription;
bool isClosing = false;
static const _syncDuration = Duration(milliseconds: 250);
final _updateSelectionDebounce = Debounce(duration: _syncDuration);
final _syncThrottle = Throttler(duration: _syncDuration);
feat: integrate new editor (#2536) * feat: update editor * feat: integrate new editor * feat: integrate the document2 into folder2 * feat: integrate the new editor * chore: cargo fix * chore: active document feature for flowy-error * feat: convert the editor action to collab action * feat: migrate the grid and board * feat: migrate the callout block * feat: migrate the divider * chore: migrate the callout and math equation * feat: migrate the code block * feat: add shift + enter command in code block * feat: support tab and shift+tab in code block * fix: cursor error after inserting divider * feat: migrate the grid and board * feat: migrate the emoji picker * feat: migrate openai * feat: integrate floating toolbar * feat: migrate the smart editor * feat: migrate the cover * feat: add option block action * chore: implement block selection and delete option * feat: support background color * feat: dismiss color picker afer setting color * feat: migrate the cover block * feat: resize the font * chore: cutomsize the padding * chore: wrap the option button with ignore widget * feat: customize the heading style * chore: optimize the divider line height * fix: the option button can't dismiss * ci: rust test * chore: flutter analyze * fix: code block selection * fix: dismiss the emoji picker after selecting one * chore: optimize the transaction adapter * fix: can't save the new content * feat: show export page when some errors happen * feat: implement get_view_data for document --------- Co-authored-by: nathan <nathan@appflowy.io>
2023-05-16 14:58:24 +08:00
// The conflict handle logic is not fully implemented yet
// use the syncTimer to force to reload the document state when the conflict happens.
Timer? _syncTimer;
bool get isLocalMode {
final userProfilePB = state.userProfilePB;
final type = userProfilePB?.authenticator ?? AuthenticatorPB.Local;
return type == AuthenticatorPB.Local;
}
feat: integrate new editor (#2536) * feat: update editor * feat: integrate new editor * feat: integrate the document2 into folder2 * feat: integrate the new editor * chore: cargo fix * chore: active document feature for flowy-error * feat: convert the editor action to collab action * feat: migrate the grid and board * feat: migrate the callout block * feat: migrate the divider * chore: migrate the callout and math equation * feat: migrate the code block * feat: add shift + enter command in code block * feat: support tab and shift+tab in code block * fix: cursor error after inserting divider * feat: migrate the grid and board * feat: migrate the emoji picker * feat: migrate openai * feat: integrate floating toolbar * feat: migrate the smart editor * feat: migrate the cover * feat: add option block action * chore: implement block selection and delete option * feat: support background color * feat: dismiss color picker afer setting color * feat: migrate the cover block * feat: resize the font * chore: cutomsize the padding * chore: wrap the option button with ignore widget * feat: customize the heading style * chore: optimize the divider line height * fix: the option button can't dismiss * ci: rust test * chore: flutter analyze * fix: code block selection * fix: dismiss the emoji picker after selecting one * chore: optimize the transaction adapter * fix: can't save the new content * feat: show export page when some errors happen * feat: implement get_view_data for document --------- Co-authored-by: nathan <nathan@appflowy.io>
2023-05-16 14:58:24 +08:00
@override
Future<void> close() async {
isClosing = true;
await checkDocumentIntegrity();
await _cancelSubscriptions();
_clearEditorState();
return super.close();
}
Future<void> _cancelSubscriptions() async {
await _documentService.syncAwarenessStates(documentId: documentId);
await _documentListener.stop();
await _syncStateListener.stop();
await _viewListener?.stop();
await _transactionSubscription?.cancel();
await _documentService.closeDocument(viewId: documentId);
}
void _clearEditorState() {
_updateSelectionDebounce.dispose();
_syncThrottle.dispose();
_syncTimer?.cancel();
_syncTimer = null;
2024-11-04 03:26:48 +01:00
state.editorState?.selectionNotifier
.removeListener(_debounceOnSelectionUpdate);
state.editorState?.service.keyboardService?.closeKeyboard();
state.editorState?.dispose();
2021-10-19 13:56:11 +08:00
}
feat: integrate new editor (#2536) * feat: update editor * feat: integrate new editor * feat: integrate the document2 into folder2 * feat: integrate the new editor * chore: cargo fix * chore: active document feature for flowy-error * feat: convert the editor action to collab action * feat: migrate the grid and board * feat: migrate the callout block * feat: migrate the divider * chore: migrate the callout and math equation * feat: migrate the code block * feat: add shift + enter command in code block * feat: support tab and shift+tab in code block * fix: cursor error after inserting divider * feat: migrate the grid and board * feat: migrate the emoji picker * feat: migrate openai * feat: integrate floating toolbar * feat: migrate the smart editor * feat: migrate the cover * feat: add option block action * chore: implement block selection and delete option * feat: support background color * feat: dismiss color picker afer setting color * feat: migrate the cover block * feat: resize the font * chore: cutomsize the padding * chore: wrap the option button with ignore widget * feat: customize the heading style * chore: optimize the divider line height * fix: the option button can't dismiss * ci: rust test * chore: flutter analyze * fix: code block selection * fix: dismiss the emoji picker after selecting one * chore: optimize the transaction adapter * fix: can't save the new content * feat: show export page when some errors happen * feat: implement get_view_data for document --------- Co-authored-by: nathan <nathan@appflowy.io>
2023-05-16 14:58:24 +08:00
Future<void> _onDocumentEvent(
DocumentEvent event,
Emitter<DocumentState> emit,
) async {
await event.when(
initial: () async {
final result = await _fetchDocumentState();
_onViewChanged();
_onDocumentChanged();
final newState = await result.fold(
(s) async {
2024-03-21 11:02:03 +07:00
final userProfilePB =
await getIt<AuthService>().getUser().toNullable();
return state.copyWith(
error: null,
editorState: s,
isLoading: false,
userProfilePB: userProfilePB,
);
},
2024-03-21 11:02:03 +07:00
(f) async => state.copyWith(
error: f,
editorState: null,
isLoading: false,
),
);
2024-03-21 11:02:03 +07:00
emit(newState);
if (newState.userProfilePB != null) {
await _updateCollaborator();
}
2022-10-22 21:57:44 +08:00
},
moveToTrash: () async {
feat: integrate new editor (#2536) * feat: update editor * feat: integrate new editor * feat: integrate the document2 into folder2 * feat: integrate the new editor * chore: cargo fix * chore: active document feature for flowy-error * feat: convert the editor action to collab action * feat: migrate the grid and board * feat: migrate the callout block * feat: migrate the divider * chore: migrate the callout and math equation * feat: migrate the code block * feat: add shift + enter command in code block * feat: support tab and shift+tab in code block * fix: cursor error after inserting divider * feat: migrate the grid and board * feat: migrate the emoji picker * feat: migrate openai * feat: integrate floating toolbar * feat: migrate the smart editor * feat: migrate the cover * feat: add option block action * chore: implement block selection and delete option * feat: support background color * feat: dismiss color picker afer setting color * feat: migrate the cover block * feat: resize the font * chore: cutomsize the padding * chore: wrap the option button with ignore widget * feat: customize the heading style * chore: optimize the divider line height * fix: the option button can't dismiss * ci: rust test * chore: flutter analyze * fix: code block selection * fix: dismiss the emoji picker after selecting one * chore: optimize the transaction adapter * fix: can't save the new content * feat: show export page when some errors happen * feat: implement get_view_data for document --------- Co-authored-by: nathan <nathan@appflowy.io>
2023-05-16 14:58:24 +08:00
emit(state.copyWith(isDeleted: true));
},
restore: () async {
feat: integrate new editor (#2536) * feat: update editor * feat: integrate new editor * feat: integrate the document2 into folder2 * feat: integrate the new editor * chore: cargo fix * chore: active document feature for flowy-error * feat: convert the editor action to collab action * feat: migrate the grid and board * feat: migrate the callout block * feat: migrate the divider * chore: migrate the callout and math equation * feat: migrate the code block * feat: add shift + enter command in code block * feat: support tab and shift+tab in code block * fix: cursor error after inserting divider * feat: migrate the grid and board * feat: migrate the emoji picker * feat: migrate openai * feat: integrate floating toolbar * feat: migrate the smart editor * feat: migrate the cover * feat: add option block action * chore: implement block selection and delete option * feat: support background color * feat: dismiss color picker afer setting color * feat: migrate the cover block * feat: resize the font * chore: cutomsize the padding * chore: wrap the option button with ignore widget * feat: customize the heading style * chore: optimize the divider line height * fix: the option button can't dismiss * ci: rust test * chore: flutter analyze * fix: code block selection * fix: dismiss the emoji picker after selecting one * chore: optimize the transaction adapter * fix: can't save the new content * feat: show export page when some errors happen * feat: implement get_view_data for document --------- Co-authored-by: nathan <nathan@appflowy.io>
2023-05-16 14:58:24 +08:00
emit(state.copyWith(isDeleted: false));
},
deletePermanently: () async {
if (databaseViewId == null && rowId == null) {
final result = await _trashService.deleteViews([documentId]);
final forceClose = result.fold((l) => true, (r) => false);
emit(state.copyWith(forceClose: forceClose));
}
feat: integrate new editor (#2536) * feat: update editor * feat: integrate new editor * feat: integrate the document2 into folder2 * feat: integrate the new editor * chore: cargo fix * chore: active document feature for flowy-error * feat: convert the editor action to collab action * feat: migrate the grid and board * feat: migrate the callout block * feat: migrate the divider * chore: migrate the callout and math equation * feat: migrate the code block * feat: add shift + enter command in code block * feat: support tab and shift+tab in code block * fix: cursor error after inserting divider * feat: migrate the grid and board * feat: migrate the emoji picker * feat: migrate openai * feat: integrate floating toolbar * feat: migrate the smart editor * feat: migrate the cover * feat: add option block action * chore: implement block selection and delete option * feat: support background color * feat: dismiss color picker afer setting color * feat: migrate the cover block * feat: resize the font * chore: cutomsize the padding * chore: wrap the option button with ignore widget * feat: customize the heading style * chore: optimize the divider line height * fix: the option button can't dismiss * ci: rust test * chore: flutter analyze * fix: code block selection * fix: dismiss the emoji picker after selecting one * chore: optimize the transaction adapter * fix: can't save the new content * feat: show export page when some errors happen * feat: implement get_view_data for document --------- Co-authored-by: nathan <nathan@appflowy.io>
2023-05-16 14:58:24 +08:00
},
restorePage: () async {
if (databaseViewId == null && rowId == null) {
final result = await TrashService.putback(documentId);
final isDeleted = result.fold((l) => false, (r) => true);
emit(state.copyWith(isDeleted: isDeleted));
}
2022-10-22 21:57:44 +08:00
},
syncStateChanged: (syncState) {
emit(state.copyWith(syncState: syncState.value));
},
clearAwarenessStates: () async {
// sync a null selection and a null meta to clear the awareness states
await _documentService.syncAwarenessStates(
documentId: documentId,
);
},
syncAwarenessStates: () async {
await _updateCollaborator();
},
2022-10-22 21:57:44 +08:00
);
}
feat: integrate new editor (#2536) * feat: update editor * feat: integrate new editor * feat: integrate the document2 into folder2 * feat: integrate the new editor * chore: cargo fix * chore: active document feature for flowy-error * feat: convert the editor action to collab action * feat: migrate the grid and board * feat: migrate the callout block * feat: migrate the divider * chore: migrate the callout and math equation * feat: migrate the code block * feat: add shift + enter command in code block * feat: support tab and shift+tab in code block * fix: cursor error after inserting divider * feat: migrate the grid and board * feat: migrate the emoji picker * feat: migrate openai * feat: integrate floating toolbar * feat: migrate the smart editor * feat: migrate the cover * feat: add option block action * chore: implement block selection and delete option * feat: support background color * feat: dismiss color picker afer setting color * feat: migrate the cover block * feat: resize the font * chore: cutomsize the padding * chore: wrap the option button with ignore widget * feat: customize the heading style * chore: optimize the divider line height * fix: the option button can't dismiss * ci: rust test * chore: flutter analyze * fix: code block selection * fix: dismiss the emoji picker after selecting one * chore: optimize the transaction adapter * fix: can't save the new content * feat: show export page when some errors happen * feat: implement get_view_data for document --------- Co-authored-by: nathan <nathan@appflowy.io>
2023-05-16 14:58:24 +08:00
/// subscribe to the view(document page) change
void _onViewChanged() {
_viewListener?.start(
onViewMoveToTrash: (r) {
r.map((r) => add(const DocumentEvent.moveToTrash()));
},
onViewDeleted: (r) {
r.map((r) => add(const DocumentEvent.moveToTrash()));
},
onViewRestored: (r) => r.map((r) => add(const DocumentEvent.restore())),
feat: integrate new editor (#2536) * feat: update editor * feat: integrate new editor * feat: integrate the document2 into folder2 * feat: integrate the new editor * chore: cargo fix * chore: active document feature for flowy-error * feat: convert the editor action to collab action * feat: migrate the grid and board * feat: migrate the callout block * feat: migrate the divider * chore: migrate the callout and math equation * feat: migrate the code block * feat: add shift + enter command in code block * feat: support tab and shift+tab in code block * fix: cursor error after inserting divider * feat: migrate the grid and board * feat: migrate the emoji picker * feat: migrate openai * feat: integrate floating toolbar * feat: migrate the smart editor * feat: migrate the cover * feat: add option block action * chore: implement block selection and delete option * feat: support background color * feat: dismiss color picker afer setting color * feat: migrate the cover block * feat: resize the font * chore: cutomsize the padding * chore: wrap the option button with ignore widget * feat: customize the heading style * chore: optimize the divider line height * fix: the option button can't dismiss * ci: rust test * chore: flutter analyze * fix: code block selection * fix: dismiss the emoji picker after selecting one * chore: optimize the transaction adapter * fix: can't save the new content * feat: show export page when some errors happen * feat: implement get_view_data for document --------- Co-authored-by: nathan <nathan@appflowy.io>
2023-05-16 14:58:24 +08:00
);
}
/// subscribe to the document content change
void _onDocumentChanged() {
_documentListener.start(
2024-04-08 14:06:05 +08:00
onDocEventUpdate: _throttleSyncDoc,
onDocAwarenessUpdate: _onAwarenessStatesUpdate,
2022-05-05 21:15:01 +08:00
);
_syncStateListener.start(
didReceiveSyncState: (syncState) {
if (!isClosed) {
add(DocumentEvent.syncStateChanged(syncState));
}
},
);
}
feat: integrate new editor (#2536) * feat: update editor * feat: integrate new editor * feat: integrate the document2 into folder2 * feat: integrate the new editor * chore: cargo fix * chore: active document feature for flowy-error * feat: convert the editor action to collab action * feat: migrate the grid and board * feat: migrate the callout block * feat: migrate the divider * chore: migrate the callout and math equation * feat: migrate the code block * feat: add shift + enter command in code block * feat: support tab and shift+tab in code block * fix: cursor error after inserting divider * feat: migrate the grid and board * feat: migrate the emoji picker * feat: migrate openai * feat: integrate floating toolbar * feat: migrate the smart editor * feat: migrate the cover * feat: add option block action * chore: implement block selection and delete option * feat: support background color * feat: dismiss color picker afer setting color * feat: migrate the cover block * feat: resize the font * chore: cutomsize the padding * chore: wrap the option button with ignore widget * feat: customize the heading style * chore: optimize the divider line height * fix: the option button can't dismiss * ci: rust test * chore: flutter analyze * fix: code block selection * fix: dismiss the emoji picker after selecting one * chore: optimize the transaction adapter * fix: can't save the new content * feat: show export page when some errors happen * feat: implement get_view_data for document --------- Co-authored-by: nathan <nathan@appflowy.io>
2023-05-16 14:58:24 +08:00
/// Fetch document
Future<FlowyResult<EditorState?, FlowyError>> _fetchDocumentState() async {
final result = await _documentService.openDocument(documentId: documentId);
return result.fold(
(s) async => FlowyResult.success(await _initAppFlowyEditorState(s)),
(e) => FlowyResult.failure(e),
);
}
Future<EditorState?> _initAppFlowyEditorState(DocumentDataPB data) async {
if (enableDocumentInternalLog) {
Log.info('document data: ${data.toProto3Json()}');
}
feat: integrate new editor (#2536) * feat: update editor * feat: integrate new editor * feat: integrate the document2 into folder2 * feat: integrate the new editor * chore: cargo fix * chore: active document feature for flowy-error * feat: convert the editor action to collab action * feat: migrate the grid and board * feat: migrate the callout block * feat: migrate the divider * chore: migrate the callout and math equation * feat: migrate the code block * feat: add shift + enter command in code block * feat: support tab and shift+tab in code block * fix: cursor error after inserting divider * feat: migrate the grid and board * feat: migrate the emoji picker * feat: migrate openai * feat: integrate floating toolbar * feat: migrate the smart editor * feat: migrate the cover * feat: add option block action * chore: implement block selection and delete option * feat: support background color * feat: dismiss color picker afer setting color * feat: migrate the cover block * feat: resize the font * chore: cutomsize the padding * chore: wrap the option button with ignore widget * feat: customize the heading style * chore: optimize the divider line height * fix: the option button can't dismiss * ci: rust test * chore: flutter analyze * fix: code block selection * fix: dismiss the emoji picker after selecting one * chore: optimize the transaction adapter * fix: can't save the new content * feat: show export page when some errors happen * feat: implement get_view_data for document --------- Co-authored-by: nathan <nathan@appflowy.io>
2023-05-16 14:58:24 +08:00
final document = data.toDocument();
if (document == null) {
assert(false, 'document is null');
return null;
feat: integrate new editor (#2536) * feat: update editor * feat: integrate new editor * feat: integrate the document2 into folder2 * feat: integrate the new editor * chore: cargo fix * chore: active document feature for flowy-error * feat: convert the editor action to collab action * feat: migrate the grid and board * feat: migrate the callout block * feat: migrate the divider * chore: migrate the callout and math equation * feat: migrate the code block * feat: add shift + enter command in code block * feat: support tab and shift+tab in code block * fix: cursor error after inserting divider * feat: migrate the grid and board * feat: migrate the emoji picker * feat: migrate openai * feat: integrate floating toolbar * feat: migrate the smart editor * feat: migrate the cover * feat: add option block action * chore: implement block selection and delete option * feat: support background color * feat: dismiss color picker afer setting color * feat: migrate the cover block * feat: resize the font * chore: cutomsize the padding * chore: wrap the option button with ignore widget * feat: customize the heading style * chore: optimize the divider line height * fix: the option button can't dismiss * ci: rust test * chore: flutter analyze * fix: code block selection * fix: dismiss the emoji picker after selecting one * chore: optimize the transaction adapter * fix: can't save the new content * feat: show export page when some errors happen * feat: implement get_view_data for document --------- Co-authored-by: nathan <nathan@appflowy.io>
2023-05-16 14:58:24 +08:00
}
final editorState = EditorState(document: document);
_documentCollabAdapter = DocumentCollabAdapter(editorState, documentId);
feat: integrate new editor (#2536) * feat: update editor * feat: integrate new editor * feat: integrate the document2 into folder2 * feat: integrate the new editor * chore: cargo fix * chore: active document feature for flowy-error * feat: convert the editor action to collab action * feat: migrate the grid and board * feat: migrate the callout block * feat: migrate the divider * chore: migrate the callout and math equation * feat: migrate the code block * feat: add shift + enter command in code block * feat: support tab and shift+tab in code block * fix: cursor error after inserting divider * feat: migrate the grid and board * feat: migrate the emoji picker * feat: migrate openai * feat: integrate floating toolbar * feat: migrate the smart editor * feat: migrate the cover * feat: add option block action * chore: implement block selection and delete option * feat: support background color * feat: dismiss color picker afer setting color * feat: migrate the cover block * feat: resize the font * chore: cutomsize the padding * chore: wrap the option button with ignore widget * feat: customize the heading style * chore: optimize the divider line height * fix: the option button can't dismiss * ci: rust test * chore: flutter analyze * fix: code block selection * fix: dismiss the emoji picker after selecting one * chore: optimize the transaction adapter * fix: can't save the new content * feat: show export page when some errors happen * feat: implement get_view_data for document --------- Co-authored-by: nathan <nathan@appflowy.io>
2023-05-16 14:58:24 +08:00
// subscribe to the document change from the editor
_transactionSubscription = editorState.transactionStream.listen(
(event) async {
final time = event.$1;
final transaction = event.$2;
if (time != TransactionTime.before) {
return;
}
if (enableDocumentInternalLog) {
Log.debug(
'[TransactionAdapter] 1. transaction before apply: ${transaction.hashCode}',
);
}
// apply transaction to backend
await _transactionAdapter.apply(transaction, editorState);
// check if the document is empty.
await _applyRules();
if (enableDocumentInternalLog) {
Log.debug(
'[TransactionAdapter] 4. transaction after apply: ${transaction.hashCode}',
);
}
if (!isClosed) {
// ignore: invalid_use_of_visible_for_testing_member
emit(state.copyWith(isDocumentEmpty: editorState.document.isEmpty));
}
},
);
editorState.selectionNotifier.addListener(_debounceOnSelectionUpdate);
feat: integrate new editor (#2536) * feat: update editor * feat: integrate new editor * feat: integrate the document2 into folder2 * feat: integrate the new editor * chore: cargo fix * chore: active document feature for flowy-error * feat: convert the editor action to collab action * feat: migrate the grid and board * feat: migrate the callout block * feat: migrate the divider * chore: migrate the callout and math equation * feat: migrate the code block * feat: add shift + enter command in code block * feat: support tab and shift+tab in code block * fix: cursor error after inserting divider * feat: migrate the grid and board * feat: migrate the emoji picker * feat: migrate openai * feat: integrate floating toolbar * feat: migrate the smart editor * feat: migrate the cover * feat: add option block action * chore: implement block selection and delete option * feat: support background color * feat: dismiss color picker afer setting color * feat: migrate the cover block * feat: resize the font * chore: cutomsize the padding * chore: wrap the option button with ignore widget * feat: customize the heading style * chore: optimize the divider line height * fix: the option button can't dismiss * ci: rust test * chore: flutter analyze * fix: code block selection * fix: dismiss the emoji picker after selecting one * chore: optimize the transaction adapter * fix: can't save the new content * feat: show export page when some errors happen * feat: implement get_view_data for document --------- Co-authored-by: nathan <nathan@appflowy.io>
2023-05-16 14:58:24 +08:00
// output the log from the editor when debug mode
if (kDebugMode) {
feat: integrate new editor (#2536) * feat: update editor * feat: integrate new editor * feat: integrate the document2 into folder2 * feat: integrate the new editor * chore: cargo fix * chore: active document feature for flowy-error * feat: convert the editor action to collab action * feat: migrate the grid and board * feat: migrate the callout block * feat: migrate the divider * chore: migrate the callout and math equation * feat: migrate the code block * feat: add shift + enter command in code block * feat: support tab and shift+tab in code block * fix: cursor error after inserting divider * feat: migrate the grid and board * feat: migrate the emoji picker * feat: migrate openai * feat: integrate floating toolbar * feat: migrate the smart editor * feat: migrate the cover * feat: add option block action * chore: implement block selection and delete option * feat: support background color * feat: dismiss color picker afer setting color * feat: migrate the cover block * feat: resize the font * chore: cutomsize the padding * chore: wrap the option button with ignore widget * feat: customize the heading style * chore: optimize the divider line height * fix: the option button can't dismiss * ci: rust test * chore: flutter analyze * fix: code block selection * fix: dismiss the emoji picker after selecting one * chore: optimize the transaction adapter * fix: can't save the new content * feat: show export page when some errors happen * feat: implement get_view_data for document --------- Co-authored-by: nathan <nathan@appflowy.io>
2023-05-16 14:58:24 +08:00
editorState.logConfiguration
..level = AppFlowyEditorLogLevel.all
feat: integrate new editor (#2536) * feat: update editor * feat: integrate new editor * feat: integrate the document2 into folder2 * feat: integrate the new editor * chore: cargo fix * chore: active document feature for flowy-error * feat: convert the editor action to collab action * feat: migrate the grid and board * feat: migrate the callout block * feat: migrate the divider * chore: migrate the callout and math equation * feat: migrate the code block * feat: add shift + enter command in code block * feat: support tab and shift+tab in code block * fix: cursor error after inserting divider * feat: migrate the grid and board * feat: migrate the emoji picker * feat: migrate openai * feat: integrate floating toolbar * feat: migrate the smart editor * feat: migrate the cover * feat: add option block action * chore: implement block selection and delete option * feat: support background color * feat: dismiss color picker afer setting color * feat: migrate the cover block * feat: resize the font * chore: cutomsize the padding * chore: wrap the option button with ignore widget * feat: customize the heading style * chore: optimize the divider line height * fix: the option button can't dismiss * ci: rust test * chore: flutter analyze * fix: code block selection * fix: dismiss the emoji picker after selecting one * chore: optimize the transaction adapter * fix: can't save the new content * feat: show export page when some errors happen * feat: implement get_view_data for document --------- Co-authored-by: nathan <nathan@appflowy.io>
2023-05-16 14:58:24 +08:00
..handler = (log) {
if (enableDocumentInternalLog) {
Log.info(log);
}
feat: integrate new editor (#2536) * feat: update editor * feat: integrate new editor * feat: integrate the document2 into folder2 * feat: integrate the new editor * chore: cargo fix * chore: active document feature for flowy-error * feat: convert the editor action to collab action * feat: migrate the grid and board * feat: migrate the callout block * feat: migrate the divider * chore: migrate the callout and math equation * feat: migrate the code block * feat: add shift + enter command in code block * feat: support tab and shift+tab in code block * fix: cursor error after inserting divider * feat: migrate the grid and board * feat: migrate the emoji picker * feat: migrate openai * feat: integrate floating toolbar * feat: migrate the smart editor * feat: migrate the cover * feat: add option block action * chore: implement block selection and delete option * feat: support background color * feat: dismiss color picker afer setting color * feat: migrate the cover block * feat: resize the font * chore: cutomsize the padding * chore: wrap the option button with ignore widget * feat: customize the heading style * chore: optimize the divider line height * fix: the option button can't dismiss * ci: rust test * chore: flutter analyze * fix: code block selection * fix: dismiss the emoji picker after selecting one * chore: optimize the transaction adapter * fix: can't save the new content * feat: show export page when some errors happen * feat: implement get_view_data for document --------- Co-authored-by: nathan <nathan@appflowy.io>
2023-05-16 14:58:24 +08:00
};
}
return editorState;
}
Future<void> _applyRules() async {
await Future.wait([
_ensureAtLeastOneParagraphExists(),
]);
}
Future<void> _ensureAtLeastOneParagraphExists() async {
final editorState = state.editorState;
if (editorState == null) {
return;
}
final document = editorState.document;
if (document.root.children.isEmpty) {
final transaction = editorState.transaction;
transaction.insertNode([0], paragraphNode());
2023-08-17 14:50:48 +08:00
transaction.afterSelection = Selection.collapsed(
Position(path: [0]),
2023-08-17 14:50:48 +08:00
);
await editorState.apply(transaction);
}
}
Future<void> _onDocumentStateUpdate(DocEventPB docEvent) async {
if (!docEvent.isRemote || !FeatureFlag.syncDocument.isOn) {
return;
2024-03-21 11:02:03 +07:00
}
unawaited(_documentCollabAdapter.syncV3(docEvent: docEvent));
}
Future<void> _onAwarenessStatesUpdate(
DocumentAwarenessStatesPB awarenessStates,
) async {
if (!FeatureFlag.syncDocument.isOn) {
return;
}
final userId = state.userProfilePB?.id;
if (userId != null) {
await _documentCollabAdapter.updateRemoteSelection(
userId.toString(),
awarenessStates,
);
}
}
void _debounceOnSelectionUpdate() {
_updateSelectionDebounce.call(_onSelectionUpdate);
}
2024-04-08 14:06:05 +08:00
void _throttleSyncDoc(DocEventPB docEvent) {
_syncThrottle.call(() {
_onDocumentStateUpdate(docEvent);
});
}
Future<void> _onSelectionUpdate() async {
if (isClosing) {
return;
}
final user = state.userProfilePB;
final deviceId = ApplicationInfo.deviceId;
if (!FeatureFlag.syncDocument.isOn || user == null) {
return;
}
final editorState = state.editorState;
if (editorState == null) {
return;
}
final selection = editorState.selection;
// sync the selection
final id = user.id.toString() + deviceId;
final basicColor = ColorGenerator(id.toString()).toColor();
final metadata = DocumentAwarenessMetadata(
cursorColor: basicColor.toHexString(),
selectionColor: basicColor.withOpacity(0.6).toHexString(),
userName: user.name,
userAvatar: user.iconUrl,
);
await _documentService.syncAwarenessStates(
documentId: documentId,
selection: selection,
metadata: jsonEncode(metadata.toJson()),
);
}
Future<void> _updateCollaborator() async {
final user = state.userProfilePB;
final deviceId = ApplicationInfo.deviceId;
if (!FeatureFlag.syncDocument.isOn || user == null) {
return;
}
// sync the selection
final id = user.id.toString() + deviceId;
final basicColor = ColorGenerator(id.toString()).toColor();
final metadata = DocumentAwarenessMetadata(
cursorColor: basicColor.toHexString(),
selectionColor: basicColor.withOpacity(0.6).toHexString(),
userName: user.name,
userAvatar: user.iconUrl,
);
await _documentService.syncAwarenessStates(
documentId: documentId,
metadata: jsonEncode(metadata.toJson()),
);
}
// this is only used for debug mode
Future<void> checkDocumentIntegrity() async {
if (!enableDocumentInternalLog) {
return;
}
final cloudDocResult =
await _documentService.getDocument(documentId: documentId);
final cloudDoc = cloudDocResult.fold((s) => s, (f) => null)?.toDocument();
final localDoc = state.editorState?.document;
if (cloudDoc == null || localDoc == null) {
return;
}
final cloudJson = cloudDoc.toJson();
final localJson = localDoc.toJson();
final deepEqual = const DeepCollectionEquality().equals(
cloudJson,
localJson,
);
if (!deepEqual) {
Log.error('document integrity check failed');
// Enable it to debug the document integrity check failed
// Log.error('cloud doc: $cloudJson');
// Log.error('local doc: $localJson');
assert(false, 'document integrity check failed');
}
}
2021-07-24 18:55:13 +08:00
}
@freezed
2022-02-23 22:17:47 +08:00
class DocumentEvent with _$DocumentEvent {
const factory DocumentEvent.initial() = Initial;
const factory DocumentEvent.moveToTrash() = MoveToTrash;
2022-02-23 22:17:47 +08:00
const factory DocumentEvent.restore() = Restore;
const factory DocumentEvent.restorePage() = RestorePage;
const factory DocumentEvent.deletePermanently() = DeletePermanently;
const factory DocumentEvent.syncStateChanged(
final DocumentSyncStatePB syncState,
) = syncStateChanged;
const factory DocumentEvent.syncAwarenessStates() = SyncAwarenessStates;
const factory DocumentEvent.clearAwarenessStates() = ClearAwarenessStates;
2021-07-24 18:55:13 +08:00
}
@freezed
2022-02-23 22:17:47 +08:00
class DocumentState with _$DocumentState {
const factory DocumentState({
required final bool isDeleted,
required final bool forceClose,
required final bool isLoading,
required final DocumentSyncState syncState,
bool? isDocumentEmpty,
UserProfilePB? userProfilePB,
EditorState? editorState,
FlowyError? error,
@Default(null) DocumentAwarenessStatesPB? awarenessStates,
2022-02-23 22:17:47 +08:00
}) = _DocumentState;
2021-10-19 13:56:11 +08:00
2022-02-23 22:17:47 +08:00
factory DocumentState.initial() => const DocumentState(
isDeleted: false,
forceClose: false,
isLoading: true,
syncState: DocumentSyncState.Syncing,
);
2021-10-19 13:56:11 +08:00
}