document_page.dart 3.6 KB

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