document_page.dart 4.0 KB

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