document_page.dart 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. import 'package:app_flowy/plugins/document/presentation/plugins/board/board_menu_item.dart';
  2. import 'package:app_flowy/plugins/document/presentation/plugins/board/board_node_widget.dart';
  3. import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
  4. import 'package:appflowy_editor/appflowy_editor.dart';
  5. import 'package:appflowy_editor_plugins/appflowy_editor_plugins.dart';
  6. import 'package:flowy_infra_ui/widget/error_page.dart';
  7. import 'package:flutter/material.dart';
  8. import 'package:flutter_bloc/flutter_bloc.dart';
  9. import 'package:intl/intl.dart';
  10. import '../../startup/startup.dart';
  11. import 'application/doc_bloc.dart';
  12. import 'editor_styles.dart';
  13. import 'presentation/banner.dart';
  14. class DocumentPage extends StatefulWidget {
  15. final VoidCallback onDeleted;
  16. final ViewPB view;
  17. DocumentPage({
  18. required this.view,
  19. required this.onDeleted,
  20. Key? key,
  21. }) : super(key: ValueKey(view.id));
  22. @override
  23. State<DocumentPage> createState() => _DocumentPageState();
  24. }
  25. class _DocumentPageState extends State<DocumentPage> {
  26. late DocumentBloc documentBloc;
  27. final FocusNode _focusNode = FocusNode();
  28. @override
  29. void initState() {
  30. // The appflowy editor use Intl as localization, set the default language as fallback.
  31. Intl.defaultLocale = 'en_US';
  32. documentBloc = getIt<DocumentBloc>(param1: super.widget.view)
  33. ..add(const DocumentEvent.initial());
  34. super.initState();
  35. }
  36. @override
  37. Widget build(BuildContext context) {
  38. return MultiBlocProvider(
  39. providers: [
  40. BlocProvider<DocumentBloc>.value(value: documentBloc),
  41. ],
  42. child:
  43. BlocBuilder<DocumentBloc, DocumentState>(builder: (context, state) {
  44. return state.loadingState.map(
  45. loading: (_) => SizedBox.expand(
  46. child: Container(color: Colors.transparent),
  47. ),
  48. finish: (result) => result.successOrFail.fold(
  49. (_) {
  50. if (state.forceClose) {
  51. widget.onDeleted();
  52. return const SizedBox();
  53. } else {
  54. return _renderDocument(context, state);
  55. }
  56. },
  57. (err) => FlowyErrorPage(err.toString()),
  58. ),
  59. );
  60. }),
  61. );
  62. }
  63. @override
  64. Future<void> dispose() async {
  65. documentBloc.close();
  66. _focusNode.dispose();
  67. super.dispose();
  68. }
  69. Widget _renderDocument(BuildContext context, DocumentState state) {
  70. return Column(
  71. children: [
  72. if (state.isDeleted) _renderBanner(context),
  73. // AppFlowy Editor
  74. _renderAppFlowyEditor(
  75. context.read<DocumentBloc>().editorState,
  76. ),
  77. ],
  78. );
  79. }
  80. Widget _renderBanner(BuildContext context) {
  81. return DocumentBanner(
  82. onRestore: () =>
  83. context.read<DocumentBloc>().add(const DocumentEvent.restorePage()),
  84. onDelete: () => context
  85. .read<DocumentBloc>()
  86. .add(const DocumentEvent.deletePermanently()),
  87. );
  88. }
  89. Widget _renderAppFlowyEditor(EditorState editorState) {
  90. final theme = Theme.of(context);
  91. final editor = AppFlowyEditor(
  92. editorState: editorState,
  93. autoFocus: editorState.document.isEmpty,
  94. customBuilders: {
  95. // Divider
  96. kDividerType: DividerWidgetBuilder(),
  97. // Math Equation
  98. kMathEquationType: MathEquationNodeWidgetBuidler(),
  99. // Code Block
  100. kCodeBlockType: CodeBlockNodeWidgetBuilder(),
  101. // Board
  102. kBoardType: BoardNodeWidgetBuilder(),
  103. // Card
  104. kCalloutType: CalloutNodeWidgetBuilder(),
  105. },
  106. shortcutEvents: [
  107. // Divider
  108. insertDividerEvent,
  109. // Code Block
  110. enterInCodeBlock,
  111. ignoreKeysInCodeBlock,
  112. pasteInCodeBlock,
  113. ],
  114. selectionMenuItems: [
  115. // Divider
  116. dividerMenuItem,
  117. // Math Equation
  118. mathEquationMenuItem,
  119. // Code Block
  120. codeBlockMenuItem,
  121. // Emoji
  122. emojiMenuItem,
  123. // Board
  124. boardMenuItem,
  125. ],
  126. themeData: theme.copyWith(extensions: [
  127. ...theme.extensions.values,
  128. customEditorTheme(context),
  129. ...customPluginTheme(context),
  130. ]),
  131. );
  132. return Expanded(
  133. child: Center(
  134. child: Container(
  135. constraints: const BoxConstraints(
  136. maxWidth: double.infinity,
  137. ),
  138. child: editor,
  139. ),
  140. ),
  141. );
  142. }
  143. }