From aa58c79dbb8eef7393d2a4f583fcf79c03f2859a Mon Sep 17 00:00:00 2001 From: "Lucas.Xu" Date: Sun, 23 Oct 2022 15:05:51 +0800 Subject: [PATCH] feat: support markdown export and customize save path (#1339) --- .../plugins/doc/application/share_bloc.dart | 46 ++++++------------- .../app_flowy/lib/plugins/doc/document.dart | 28 +++++++---- .../markdown/src/delta_markdown_encoder.dart | 13 ++++-- .../flowy_infra_ui/example/pubspec.lock | 9 +++- .../pubspec.lock | 6 +-- .../flowy_infra_ui_web/pubspec.lock | 6 +-- .../packages/flowy_infra_ui/pubspec.lock | 9 +++- .../packages/flowy_sdk/example/pubspec.lock | 8 ++-- .../app_flowy/packages/flowy_sdk/pubspec.lock | 8 ++-- frontend/app_flowy/pubspec.lock | 7 +++ frontend/app_flowy/pubspec.yaml | 1 + 11 files changed, 81 insertions(+), 60 deletions(-) diff --git a/frontend/app_flowy/lib/plugins/doc/application/share_bloc.dart b/frontend/app_flowy/lib/plugins/doc/application/share_bloc.dart index a37d3eafeb..9487350522 100644 --- a/frontend/app_flowy/lib/plugins/doc/application/share_bloc.dart +++ b/frontend/app_flowy/lib/plugins/doc/application/share_bloc.dart @@ -1,7 +1,5 @@ -import 'dart:async'; import 'dart:convert'; import 'dart:io'; -import 'package:app_flowy/startup/tasks/rust_sdk.dart'; import 'package:app_flowy/plugins/doc/application/share_service.dart'; import 'package:app_flowy/workspace/application/markdown/document_markdown.dart'; import 'package:flowy_sdk/protobuf/flowy-document/entities.pb.dart'; @@ -20,11 +18,14 @@ class DocShareBloc extends Bloc { : super(const DocShareState.initial()) { on((event, emit) async { await event.map( - shareMarkdown: (ShareMarkdown value) async { + shareMarkdown: (ShareMarkdown shareMarkdown) async { await service.exportMarkdown(view).then((result) { result.fold( - (value) => emit(DocShareState.finish( - left(_convertDocumentToMarkdown(value)))), + (value) => emit( + DocShareState.finish( + left(_saveMarkdown(value, shareMarkdown.path)), + ), + ), (error) => emit(DocShareState.finish(right(error))), ); }); @@ -37,40 +38,23 @@ class DocShareBloc extends Bloc { }); } - ExportDataPB _convertDocumentToMarkdown(ExportDataPB value) { - final json = jsonDecode(value.data); - final document = Document.fromJson(json); - final result = documentToMarkdown(document); - value.data = result; - writeFile(result); + ExportDataPB _saveMarkdown(ExportDataPB value, String path) { + final markdown = _convertDocumentToMarkdown(value); + value.data = markdown; + File(path).writeAsStringSync(markdown); return value; } - Future get _exportDir async { - Directory documentsDir = await appFlowyDocumentDirectory(); - - return documentsDir; - } - - Future get _localPath async { - final dir = await _exportDir; - return dir.path; - } - - Future get _localFile async { - final path = await _localPath; - return File('$path/${view.name}.md'); - } - - Future writeFile(String md) async { - final file = await _localFile; - return file.writeAsString(md); + String _convertDocumentToMarkdown(ExportDataPB value) { + final json = jsonDecode(value.data); + final document = Document.fromJson(json); + return documentToMarkdown(document); } } @freezed class DocShareEvent with _$DocShareEvent { - const factory DocShareEvent.shareMarkdown() = ShareMarkdown; + const factory DocShareEvent.shareMarkdown(String path) = ShareMarkdown; const factory DocShareEvent.shareText() = ShareText; const factory DocShareEvent.shareLink() = ShareLink; } diff --git a/frontend/app_flowy/lib/plugins/doc/document.dart b/frontend/app_flowy/lib/plugins/doc/document.dart index 73456993be..49a5e45892 100644 --- a/frontend/app_flowy/lib/plugins/doc/document.dart +++ b/frontend/app_flowy/lib/plugins/doc/document.dart @@ -14,6 +14,7 @@ import 'package:app_flowy/workspace/presentation/widgets/pop_up_action.dart'; import 'package:appflowy_popover/appflowy_popover.dart'; import 'package:clipboard/clipboard.dart'; import 'package:easy_localization/easy_localization.dart'; +import 'package:file_picker/file_picker.dart'; import 'package:flowy_infra/size.dart'; import 'package:flowy_infra/theme.dart'; import 'package:flowy_infra_ui/widget/rounded_button.dart'; @@ -138,7 +139,9 @@ class DocumentShareButton extends StatelessWidget { height: 30, width: 100, ), - child: const ShareActionList(), + child: ShareActionList( + view: view, + ), ), ), ); @@ -165,11 +168,17 @@ class DocumentShareButton extends StatelessWidget { } class ShareActionList extends StatelessWidget { - const ShareActionList({Key? key}) : super(key: key); + const ShareActionList({ + Key? key, + required this.view, + }) : super(key: key); + + final ViewPB view; @override Widget build(BuildContext context) { final theme = context.watch(); + final docShareBloc = context.read(); return PopoverActionList( direction: PopoverDirection.bottomWithCenterAligned, actions: ShareAction.values @@ -184,14 +193,17 @@ class ShareActionList extends StatelessWidget { onPressed: () => controller.show(), ); }, - onSelected: (action, controller) { + onSelected: (action, controller) async { switch (action.inner) { case ShareAction.markdown: - context - .read() - .add(const DocShareEvent.shareMarkdown()); - showMessageToast( - 'Exported to: ${LocaleKeys.notifications_export_path.tr()}'); + final exportPath = await FilePicker.platform.saveFile( + dialogTitle: '', + fileName: '${view.name}.md', + ); + if (exportPath != null) { + docShareBloc.add(DocShareEvent.shareMarkdown(exportPath)); + showMessageToast('Exported to: $exportPath'); + } break; case ShareAction.copyLink: NavigatorAlertDialog( diff --git a/frontend/app_flowy/lib/workspace/application/markdown/src/delta_markdown_encoder.dart b/frontend/app_flowy/lib/workspace/application/markdown/src/delta_markdown_encoder.dart index bd2aa4c281..fd7880d63f 100644 --- a/frontend/app_flowy/lib/workspace/application/markdown/src/delta_markdown_encoder.dart +++ b/frontend/app_flowy/lib/workspace/application/markdown/src/delta_markdown_encoder.dart @@ -65,7 +65,8 @@ class DeltaMarkdownEncoder extends Converter { // First close any current styles if needed final markedForRemoval = []; // Close the styles in reverse order, e.g. **_ for _**Test**_. - for (final value in currentInlineStyle.attributes.values.toList().reversed) { + for (final value + in currentInlineStyle.attributes.values.toList().reversed) { // TODO(tillf): Is block correct? if (value.scope == AttributeScope.BLOCK) { continue; @@ -122,8 +123,10 @@ class DeltaMarkdownEncoder extends Converter { // Close any open inline styles. _handleInline(lineBuffer, '', null); - final lineBlock = - Style.fromJson(attributes).attributes.values.singleWhereOrNull((a) => a.scope == AttributeScope.BLOCK); + final lineBlock = Style.fromJson(attributes) + .attributes + .values + .singleWhereOrNull((a) => a.scope == AttributeScope.BLOCK); if (lineBlock == currentBlockStyle) { currentBlockLines.add(lineBuffer.toString()); @@ -228,7 +231,7 @@ class DeltaMarkdownEncoder extends Converter { } else if (attribute.key == Attribute.strikeThrough.key) { buffer.write(!close ? '~~' : '~~'); } else { - throw ArgumentError('Cannot handle $attribute'); + // do nothing, just skip the unknown attribute. } } @@ -256,7 +259,7 @@ class DeltaMarkdownEncoder extends Converter { } else if (block.key == Attribute.list.key) { buffer.write('* '); } else { - throw ArgumentError('Cannot handle block $block'); + // do nothing, just skip the unknown attribute. } } diff --git a/frontend/app_flowy/packages/flowy_infra_ui/example/pubspec.lock b/frontend/app_flowy/packages/flowy_infra_ui/example/pubspec.lock index 8ddcc99719..398e3d0c89 100644 --- a/frontend/app_flowy/packages/flowy_infra_ui/example/pubspec.lock +++ b/frontend/app_flowy/packages/flowy_infra_ui/example/pubspec.lock @@ -8,6 +8,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.0.1" + appflowy_popover: + dependency: transitive + description: + path: "../../appflowy_popover" + relative: true + source: path + version: "0.0.1" async: dependency: transitive description: @@ -234,7 +241,7 @@ packages: source: hosted version: "2.0.1" provider: - dependency: transitive + dependency: "direct main" description: name: provider url: "https://pub.dartlang.org" diff --git a/frontend/app_flowy/packages/flowy_infra_ui/flowy_infra_ui_platform_interface/pubspec.lock b/frontend/app_flowy/packages/flowy_infra_ui/flowy_infra_ui_platform_interface/pubspec.lock index 7309cce94a..f736121e48 100644 --- a/frontend/app_flowy/packages/flowy_infra_ui/flowy_infra_ui_platform_interface/pubspec.lock +++ b/frontend/app_flowy/packages/flowy_infra_ui/flowy_infra_ui_platform_interface/pubspec.lock @@ -61,7 +61,7 @@ packages: name: flutter_lints url: "https://pub.dartlang.org" source: hosted - version: "1.0.4" + version: "2.0.1" flutter_test: dependency: "direct dev" description: flutter @@ -73,7 +73,7 @@ packages: name: lints url: "https://pub.dartlang.org" source: hosted - version: "1.0.1" + version: "2.0.1" matcher: dependency: transitive description: @@ -164,5 +164,5 @@ packages: source: hosted version: "2.1.2" sdks: - dart: ">=2.17.0-0 <3.0.0" + dart: ">=2.17.0 <3.0.0" flutter: ">=1.17.0" diff --git a/frontend/app_flowy/packages/flowy_infra_ui/flowy_infra_ui_web/pubspec.lock b/frontend/app_flowy/packages/flowy_infra_ui/flowy_infra_ui_web/pubspec.lock index bdc4a1ae65..e05d8bd65c 100644 --- a/frontend/app_flowy/packages/flowy_infra_ui/flowy_infra_ui_web/pubspec.lock +++ b/frontend/app_flowy/packages/flowy_infra_ui/flowy_infra_ui_web/pubspec.lock @@ -68,7 +68,7 @@ packages: name: flutter_lints url: "https://pub.dartlang.org" source: hosted - version: "1.0.4" + version: "2.0.1" flutter_test: dependency: "direct dev" description: flutter @@ -92,7 +92,7 @@ packages: name: lints url: "https://pub.dartlang.org" source: hosted - version: "1.0.1" + version: "2.0.1" matcher: dependency: transitive description: @@ -183,5 +183,5 @@ packages: source: hosted version: "2.1.2" sdks: - dart: ">=2.17.0-0 <3.0.0" + dart: ">=2.17.0 <3.0.0" flutter: ">=1.17.0" diff --git a/frontend/app_flowy/packages/flowy_infra_ui/pubspec.lock b/frontend/app_flowy/packages/flowy_infra_ui/pubspec.lock index 143279950d..04805bd707 100644 --- a/frontend/app_flowy/packages/flowy_infra_ui/pubspec.lock +++ b/frontend/app_flowy/packages/flowy_infra_ui/pubspec.lock @@ -8,8 +8,15 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.0.1" + appflowy_popover: + dependency: "direct main" + description: + path: "../appflowy_popover" + relative: true + source: path + version: "0.0.1" async: - dependency: transitive + dependency: "direct main" description: name: async url: "https://pub.dartlang.org" diff --git a/frontend/app_flowy/packages/flowy_sdk/example/pubspec.lock b/frontend/app_flowy/packages/flowy_sdk/example/pubspec.lock index ef6b2235e4..4caaa46dea 100644 --- a/frontend/app_flowy/packages/flowy_sdk/example/pubspec.lock +++ b/frontend/app_flowy/packages/flowy_sdk/example/pubspec.lock @@ -70,7 +70,7 @@ packages: name: dartz url: "https://pub.dartlang.org" source: hosted - version: "0.10.0-nullsafety.2" + version: "0.10.1" fake_async: dependency: transitive description: @@ -122,7 +122,7 @@ packages: name: flutter_lints url: "https://pub.dartlang.org" source: hosted - version: "1.0.3" + version: "2.0.1" flutter_test: dependency: "direct dev" description: flutter @@ -165,7 +165,7 @@ packages: name: lints url: "https://pub.dartlang.org" source: hosted - version: "1.0.1" + version: "2.0.1" logger: dependency: transitive description: @@ -305,5 +305,5 @@ packages: source: hosted version: "3.0.0" sdks: - dart: ">=2.17.0-0 <3.0.0" + dart: ">=2.17.0 <3.0.0" flutter: ">=1.17.0" diff --git a/frontend/app_flowy/packages/flowy_sdk/pubspec.lock b/frontend/app_flowy/packages/flowy_sdk/pubspec.lock index 0539950c64..395abe99e6 100644 --- a/frontend/app_flowy/packages/flowy_sdk/pubspec.lock +++ b/frontend/app_flowy/packages/flowy_sdk/pubspec.lock @@ -168,7 +168,7 @@ packages: name: dartz url: "https://pub.dartlang.org" source: hosted - version: "0.10.0-nullsafety.2" + version: "0.10.1" fake_async: dependency: transitive description: @@ -208,7 +208,7 @@ packages: name: flutter_lints url: "https://pub.dartlang.org" source: hosted - version: "1.0.3" + version: "2.0.1" flutter_test: dependency: "direct dev" description: flutter @@ -290,7 +290,7 @@ packages: name: lints url: "https://pub.dartlang.org" source: hosted - version: "1.0.1" + version: "2.0.1" logger: dependency: "direct main" description: @@ -500,5 +500,5 @@ packages: source: hosted version: "3.1.0" sdks: - dart: ">=2.17.0-0 <3.0.0" + dart: ">=2.17.0 <3.0.0" flutter: ">=1.17.0" diff --git a/frontend/app_flowy/pubspec.lock b/frontend/app_flowy/pubspec.lock index 918dc043a4..823a744857 100644 --- a/frontend/app_flowy/pubspec.lock +++ b/frontend/app_flowy/pubspec.lock @@ -393,6 +393,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "6.1.2" + file_picker: + dependency: "direct main" + description: + name: file_picker + url: "https://pub.dartlang.org" + source: hosted + version: "4.6.1" fixnum: dependency: "direct main" description: diff --git a/frontend/app_flowy/pubspec.yaml b/frontend/app_flowy/pubspec.yaml index 0b4b6e9800..bb40a5c51c 100644 --- a/frontend/app_flowy/pubspec.yaml +++ b/frontend/app_flowy/pubspec.yaml @@ -92,6 +92,7 @@ dependencies: textstyle_extensions: "2.0.0-nullsafety" shared_preferences: ^2.0.15 google_fonts: ^3.0.1 + file_picker: <=5.0.0 dev_dependencies: flutter_lints: ^2.0.1