| 
									
										
										
										
											2023-05-16 14:58:24 +08:00
										 |  |  | import 'dart:convert'; | 
					
						
							|  |  |  | import 'dart:io'; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-20 16:03:39 -10:00
										 |  |  | import 'package:appflowy/generated/locale_keys.g.dart'; | 
					
						
							| 
									
										
										
										
											2023-05-16 14:58:24 +08:00
										 |  |  | import 'package:appflowy/plugins/document/application/doc_bloc.dart'; | 
					
						
							|  |  |  | import 'package:appflowy/plugins/document/presentation/banner.dart'; | 
					
						
							|  |  |  | import 'package:appflowy/plugins/document/presentation/editor_page.dart'; | 
					
						
							|  |  |  | import 'package:appflowy/plugins/document/presentation/editor_plugins/plugins.dart'; | 
					
						
							| 
									
										
										
										
											2023-06-15 16:33:44 +08:00
										 |  |  | import 'package:appflowy/plugins/document/presentation/editor_style.dart'; | 
					
						
							| 
									
										
										
										
											2023-05-16 14:58:24 +08:00
										 |  |  | import 'package:appflowy/plugins/document/presentation/export_page_widget.dart'; | 
					
						
							|  |  |  | import 'package:appflowy/startup/startup.dart'; | 
					
						
							|  |  |  | import 'package:appflowy/util/base64_string.dart'; | 
					
						
							| 
									
										
										
										
											2023-07-14 13:37:13 +08:00
										 |  |  | import 'package:appflowy_backend/log.dart'; | 
					
						
							| 
									
										
										
										
											2023-05-23 16:13:12 +08:00
										 |  |  | import 'package:appflowy_backend/protobuf/flowy-document2/protobuf.dart' | 
					
						
							|  |  |  |     hide DocumentEvent; | 
					
						
							| 
									
										
										
										
											2023-04-04 08:41:16 +08:00
										 |  |  | import 'package:appflowy_backend/protobuf/flowy-folder2/view.pb.dart'; | 
					
						
							| 
									
										
										
										
											2023-07-14 13:37:13 +08:00
										 |  |  | import 'package:appflowy_editor/appflowy_editor.dart' hide Log; | 
					
						
							| 
									
										
										
										
											2023-06-20 16:03:39 -10:00
										 |  |  | import 'package:easy_localization/easy_localization.dart'; | 
					
						
							| 
									
										
										
										
											2023-07-03 04:07:11 -10:00
										 |  |  | import 'package:flowy_infra/file_picker/file_picker_service.dart'; | 
					
						
							| 
									
										
										
										
											2023-05-16 14:58:24 +08:00
										 |  |  | import 'package:flowy_infra_ui/flowy_infra_ui.dart'; | 
					
						
							| 
									
										
										
										
											2021-10-19 13:56:11 +08:00
										 |  |  | import 'package:flowy_infra_ui/widget/error_page.dart'; | 
					
						
							| 
									
										
										
										
											2023-03-20 15:29:17 -10:00
										 |  |  | import 'package:flutter/material.dart'; | 
					
						
							| 
									
										
										
										
											2023-05-16 14:58:24 +08:00
										 |  |  | import 'package:flutter_bloc/flutter_bloc.dart'; | 
					
						
							|  |  |  | import 'package:path/path.dart' as p; | 
					
						
							| 
									
										
										
										
											2021-10-22 23:49:56 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-02-23 22:17:47 +08:00
										 |  |  | class DocumentPage extends StatefulWidget { | 
					
						
							| 
									
										
										
										
											2023-05-16 14:58:24 +08:00
										 |  |  |   const DocumentPage({ | 
					
						
							|  |  |  |     super.key, | 
					
						
							|  |  |  |     required this.onDeleted, | 
					
						
							|  |  |  |     required this.view, | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-22 13:08:48 +08:00
										 |  |  |   final VoidCallback onDeleted; | 
					
						
							| 
									
										
										
										
											2022-07-19 14:11:29 +08:00
										 |  |  |   final ViewPB view; | 
					
						
							| 
									
										
										
										
											2021-07-24 14:05:49 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-08 16:58:58 +08:00
										 |  |  |   @override | 
					
						
							| 
									
										
										
										
											2022-02-23 22:17:47 +08:00
										 |  |  |   State<DocumentPage> createState() => _DocumentPageState(); | 
					
						
							| 
									
										
										
										
											2021-10-08 16:58:58 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-02-23 22:17:47 +08:00
										 |  |  | class _DocumentPageState extends State<DocumentPage> { | 
					
						
							| 
									
										
										
										
											2023-05-16 14:58:24 +08:00
										 |  |  |   late final DocumentBloc documentBloc; | 
					
						
							|  |  |  |   EditorState? editorState; | 
					
						
							| 
									
										
										
										
											2021-10-08 16:58:58 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-19 13:56:11 +08:00
										 |  |  |   @override | 
					
						
							|  |  |  |   void initState() { | 
					
						
							| 
									
										
										
										
											2023-05-16 14:58:24 +08:00
										 |  |  |     super.initState(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     documentBloc = getIt<DocumentBloc>(param1: widget.view) | 
					
						
							|  |  |  |       ..add(const DocumentEvent.initial()); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-26 10:38:57 +08:00
										 |  |  |     // The appflowy editor use Intl as localization, set the default language as fallback.
 | 
					
						
							| 
									
										
										
										
											2022-10-22 21:57:44 +08:00
										 |  |  |     Intl.defaultLocale = 'en_US'; | 
					
						
							| 
									
										
										
										
											2021-10-19 13:56:11 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-21 13:25:46 +08:00
										 |  |  |   @override | 
					
						
							| 
									
										
										
										
											2023-02-24 09:16:51 +08:00
										 |  |  |   void dispose() { | 
					
						
							|  |  |  |     documentBloc.close(); | 
					
						
							| 
									
										
										
										
											2023-02-21 13:25:46 +08:00
										 |  |  |     super.dispose(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-24 18:55:13 +08:00
										 |  |  |   @override | 
					
						
							|  |  |  |   Widget build(BuildContext context) { | 
					
						
							| 
									
										
										
										
											2023-05-16 14:58:24 +08:00
										 |  |  |     return BlocProvider.value( | 
					
						
							|  |  |  |       value: documentBloc, | 
					
						
							| 
									
										
										
										
											2023-04-10 15:10:42 +08:00
										 |  |  |       child: BlocBuilder<DocumentBloc, DocumentState>( | 
					
						
							|  |  |  |         builder: (context, state) { | 
					
						
							| 
									
										
										
										
											2023-05-16 14:58:24 +08:00
										 |  |  |           return state.loadingState.when( | 
					
						
							| 
									
										
										
										
											2023-08-05 15:02:05 +08:00
										 |  |  |             loading: () => | 
					
						
							|  |  |  |                 const Center(child: CircularProgressIndicator.adaptive()), | 
					
						
							| 
									
										
										
										
											2023-05-16 14:58:24 +08:00
										 |  |  |             finish: (result) => result.fold( | 
					
						
							| 
									
										
										
										
											2023-07-14 13:37:13 +08:00
										 |  |  |               (error) { | 
					
						
							|  |  |  |                 Log.error(error); | 
					
						
							|  |  |  |                 return FlowyErrorPage.message( | 
					
						
							|  |  |  |                   error.toString(), | 
					
						
							|  |  |  |                   howToFix: LocaleKeys.errorDialog_howToFixFallback.tr(), | 
					
						
							|  |  |  |                 ); | 
					
						
							|  |  |  |               }, | 
					
						
							| 
									
										
										
										
											2023-05-16 14:58:24 +08:00
										 |  |  |               (data) { | 
					
						
							| 
									
										
										
										
											2023-04-10 15:10:42 +08:00
										 |  |  |                 if (state.forceClose) { | 
					
						
							|  |  |  |                   widget.onDeleted(); | 
					
						
							| 
									
										
										
										
											2023-05-16 14:58:24 +08:00
										 |  |  |                   return const SizedBox.shrink(); | 
					
						
							| 
									
										
										
										
											2023-04-10 15:10:42 +08:00
										 |  |  |                 } else if (documentBloc.editorState == null) { | 
					
						
							| 
									
										
										
										
											2023-05-16 14:58:24 +08:00
										 |  |  |                   return Center( | 
					
						
							|  |  |  |                     child: ExportPageWidget( | 
					
						
							|  |  |  |                       onTap: () async => await _exportPage(data), | 
					
						
							|  |  |  |                     ), | 
					
						
							|  |  |  |                   ); | 
					
						
							| 
									
										
										
										
											2023-04-10 15:10:42 +08:00
										 |  |  |                 } else { | 
					
						
							| 
									
										
										
										
											2023-05-16 14:58:24 +08:00
										 |  |  |                   editorState = documentBloc.editorState!; | 
					
						
							|  |  |  |                   return _buildEditorPage(context, state); | 
					
						
							| 
									
										
										
										
											2023-04-10 15:10:42 +08:00
										 |  |  |                 } | 
					
						
							|  |  |  |               }, | 
					
						
							|  |  |  |             ), | 
					
						
							|  |  |  |           ); | 
					
						
							|  |  |  |         }, | 
					
						
							|  |  |  |       ), | 
					
						
							| 
									
										
										
										
											2021-07-24 14:05:49 +08:00
										 |  |  |     ); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-16 14:58:24 +08:00
										 |  |  |   Widget _buildEditorPage(BuildContext context, DocumentState state) { | 
					
						
							|  |  |  |     final appflowyEditorPage = AppFlowyEditorPage( | 
					
						
							|  |  |  |       editorState: editorState!, | 
					
						
							| 
									
										
										
										
											2023-06-15 16:33:44 +08:00
										 |  |  |       styleCustomizer: EditorStyleCustomizer( | 
					
						
							|  |  |  |         context: context, | 
					
						
							| 
									
										
										
										
											2023-08-30 17:21:32 +08:00
										 |  |  |         // the 44 is the width of the left action list
 | 
					
						
							|  |  |  |         padding: const EdgeInsets.only(left: 40, right: 40 + 44), | 
					
						
							| 
									
										
										
										
											2023-06-15 16:33:44 +08:00
										 |  |  |       ), | 
					
						
							| 
									
										
										
										
											2023-05-17 11:02:55 +08:00
										 |  |  |       header: _buildCoverAndIcon(context), | 
					
						
							| 
									
										
										
										
											2023-05-16 14:58:24 +08:00
										 |  |  |     ); | 
					
						
							| 
									
										
										
										
											2022-11-14 15:31:39 +08:00
										 |  |  |     return Column( | 
					
						
							|  |  |  |       children: [ | 
					
						
							| 
									
										
										
										
											2023-05-16 14:58:24 +08:00
										 |  |  |         if (state.isDeleted) _buildBanner(context), | 
					
						
							|  |  |  |         Expanded( | 
					
						
							|  |  |  |           child: appflowyEditorPage, | 
					
						
							|  |  |  |         ), | 
					
						
							| 
									
										
										
										
											2022-11-14 15:31:39 +08:00
										 |  |  |       ], | 
					
						
							| 
									
										
										
										
											2021-10-31 19:48:20 +08:00
										 |  |  |     ); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-16 14:58:24 +08:00
										 |  |  |   Widget _buildBanner(BuildContext context) { | 
					
						
							| 
									
										
										
										
											2022-02-23 22:17:47 +08:00
										 |  |  |     return DocumentBanner( | 
					
						
							| 
									
										
										
										
											2023-05-16 14:58:24 +08:00
										 |  |  |       onRestore: () => documentBloc.add(const DocumentEvent.restorePage()), | 
					
						
							|  |  |  |       onDelete: () => documentBloc.add(const DocumentEvent.deletePermanently()), | 
					
						
							| 
									
										
										
										
											2021-10-31 19:48:20 +08:00
										 |  |  |     ); | 
					
						
							| 
									
										
										
										
											2021-10-08 16:58:58 +08:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2023-02-16 10:17:08 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-16 14:58:24 +08:00
										 |  |  |   Widget _buildCoverAndIcon(BuildContext context) { | 
					
						
							|  |  |  |     if (editorState == null) { | 
					
						
							|  |  |  |       return const Placeholder(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     final page = editorState!.document.root; | 
					
						
							| 
									
										
										
										
											2023-06-27 15:17:51 +08:00
										 |  |  |     return DocumentHeaderNodeWidget( | 
					
						
							| 
									
										
										
										
											2023-05-16 14:58:24 +08:00
										 |  |  |       node: page, | 
					
						
							|  |  |  |       editorState: editorState!, | 
					
						
							| 
									
										
										
										
											2021-07-24 14:05:49 +08:00
										 |  |  |     ); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2023-02-21 13:25:46 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-23 16:13:12 +08:00
										 |  |  |   Future<void> _exportPage(DocumentDataPB data) async { | 
					
						
							| 
									
										
										
										
											2023-05-16 14:58:24 +08:00
										 |  |  |     final picker = getIt<FilePickerService>(); | 
					
						
							|  |  |  |     final dir = await picker.getDirectoryPath(); | 
					
						
							|  |  |  |     if (dir == null) { | 
					
						
							| 
									
										
										
										
											2023-02-21 13:25:46 +08:00
										 |  |  |       return; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-05-16 14:58:24 +08:00
										 |  |  |     final path = p.join(dir, '${documentBloc.view.name}.json'); | 
					
						
							|  |  |  |     const encoder = JsonEncoder.withIndent('  '); | 
					
						
							|  |  |  |     final json = encoder.convert(data.toProto3Json()); | 
					
						
							|  |  |  |     await File(path).writeAsString(json.base64.base64); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     _showMessage('Export success to $path'); | 
					
						
							| 
									
										
										
										
											2023-02-21 13:25:46 +08:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2023-03-02 16:34:22 +05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-16 14:58:24 +08:00
										 |  |  |   void _showMessage(String message) { | 
					
						
							|  |  |  |     if (!mounted) { | 
					
						
							|  |  |  |       return; | 
					
						
							| 
									
										
										
										
											2023-03-02 16:34:22 +05:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-05-16 14:58:24 +08:00
										 |  |  |     ScaffoldMessenger.of(context).showSnackBar( | 
					
						
							|  |  |  |       SnackBar( | 
					
						
							|  |  |  |         content: FlowyText(message), | 
					
						
							|  |  |  |       ), | 
					
						
							|  |  |  |     ); | 
					
						
							| 
									
										
										
										
											2023-03-02 16:34:22 +05:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2021-07-24 14:05:49 +08:00
										 |  |  | } |