From 3bb4ed6b7fb26e326153ec31b34d94e7befdcd78 Mon Sep 17 00:00:00 2001 From: "Lucas.Xu" Date: Wed, 18 Sep 2024 17:48:26 +0800 Subject: [PATCH 1/2] feat: support publish on mobile --- .../base/view_page/app_bar_buttons.dart | 6 ++ .../base/view_page/more_bottom_sheet.dart | 69 ++++++++++++++++++- .../bottom_sheet/bottom_sheet_view_page.dart | 59 +++++++++++++++- 3 files changed, 132 insertions(+), 2 deletions(-) diff --git a/frontend/appflowy_flutter/lib/mobile/presentation/base/view_page/app_bar_buttons.dart b/frontend/appflowy_flutter/lib/mobile/presentation/base/view_page/app_bar_buttons.dart index 1301719c41f3..8c49d70d0b03 100644 --- a/frontend/appflowy_flutter/lib/mobile/presentation/base/view_page/app_bar_buttons.dart +++ b/frontend/appflowy_flutter/lib/mobile/presentation/base/view_page/app_bar_buttons.dart @@ -8,6 +8,7 @@ import 'package:appflowy/mobile/presentation/base/view_page/more_bottom_sheet.da import 'package:appflowy/mobile/presentation/bottom_sheet/bottom_sheet.dart'; import 'package:appflowy/plugins/document/presentation/editor_notification.dart'; import 'package:appflowy/plugins/document/presentation/editor_plugins/page_style/page_style_bottom_sheet.dart'; +import 'package:appflowy/plugins/shared/share/share_bloc.dart'; import 'package:appflowy/workspace/application/favorite/favorite_bloc.dart'; import 'package:appflowy/workspace/application/view/prelude.dart'; import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart'; @@ -98,6 +99,11 @@ class MobileViewPageMoreButton extends StatelessWidget { providers: [ BlocProvider.value(value: context.read()), BlocProvider.value(value: context.read()), + BlocProvider.value(value: context.read()), + BlocProvider( + create: (_) => + ShareBloc(view: view)..add(const ShareEvent.initial()), + ), ], child: MobileViewPageMoreBottomSheet(view: view), ), diff --git a/frontend/appflowy_flutter/lib/mobile/presentation/base/view_page/more_bottom_sheet.dart b/frontend/appflowy_flutter/lib/mobile/presentation/base/view_page/more_bottom_sheet.dart index 6394ca964719..d0edc2e971be 100644 --- a/frontend/appflowy_flutter/lib/mobile/presentation/base/view_page/more_bottom_sheet.dart +++ b/frontend/appflowy_flutter/lib/mobile/presentation/base/view_page/more_bottom_sheet.dart @@ -1,11 +1,22 @@ +import 'dart:async'; + +import 'package:appflowy/core/helpers/url_launcher.dart'; +import 'package:appflowy/generated/locale_keys.g.dart'; import 'package:appflowy/mobile/presentation/bottom_sheet/bottom_sheet.dart'; import 'package:appflowy/plugins/document/presentation/editor_notification.dart'; +import 'package:appflowy/plugins/document/presentation/editor_plugins/copy_and_paste/clipboard_service.dart'; +import 'package:appflowy/plugins/shared/share/publish_name_generator.dart'; +import 'package:appflowy/plugins/shared/share/share_bloc.dart'; +import 'package:appflowy/startup/startup.dart'; import 'package:appflowy/workspace/application/favorite/favorite_bloc.dart'; import 'package:appflowy/workspace/application/view/prelude.dart'; +import 'package:appflowy/workspace/presentation/widgets/dialogs.dart'; import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart'; +import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:go_router/go_router.dart'; +import 'package:url_launcher/url_launcher.dart'; class MobileViewPageMoreBottomSheet extends StatelessWidget { const MobileViewPageMoreBottomSheet({super.key, required this.view}); @@ -16,7 +27,7 @@ class MobileViewPageMoreBottomSheet extends StatelessWidget { Widget build(BuildContext context) { return ViewPageBottomSheet( view: view, - onAction: (action) { + onAction: (action) async { switch (action) { case MobileViewBottomSheetBodyAction.duplicate: context.pop(); @@ -52,6 +63,62 @@ class MobileViewPageMoreBottomSheet extends StatelessWidget { // unimplemented context.pop(); break; + case MobileViewBottomSheetBodyAction.publish: + final id = context.read().view.id; + final publishName = await generatePublishName( + id, + view.name, + ); + if (context.mounted) { + context.read().add( + ShareEvent.publish( + '', + publishName, + [view.id], + ), + ); + showToastNotification( + context, + message: LocaleKeys.publish_publishSuccessfully.tr(), + ); + context.pop(); + } + break; + case MobileViewBottomSheetBodyAction.unpublish: + context.read().add(const ShareEvent.unPublish()); + showToastNotification( + context, + message: LocaleKeys.publish_unpublishSuccessfully.tr(), + ); + context.pop(); + break; + case MobileViewBottomSheetBodyAction.copyPublishLink: + final url = context.read().state.url; + if (url.isNotEmpty) { + unawaited( + getIt().setData( + ClipboardServiceData(plainText: url), + ), + ); + showToastNotification( + context, + message: LocaleKeys.grid_url_copy.tr(), + ); + } + context.pop(); + break; + case MobileViewBottomSheetBodyAction.visitSite: + final url = context.read().state.url; + if (url.isNotEmpty) { + unawaited( + afLaunchUrl( + Uri.parse(url), + mode: LaunchMode.externalApplication, + ), + ); + } + context.pop(); + break; case MobileViewBottomSheetBodyAction.rename: // no need to implement, rename is handled by the onRename callback. throw UnimplementedError(); diff --git a/frontend/appflowy_flutter/lib/mobile/presentation/bottom_sheet/bottom_sheet_view_page.dart b/frontend/appflowy_flutter/lib/mobile/presentation/bottom_sheet/bottom_sheet_view_page.dart index 62d471a093a0..0b5b0659df99 100644 --- a/frontend/appflowy_flutter/lib/mobile/presentation/bottom_sheet/bottom_sheet_view_page.dart +++ b/frontend/appflowy_flutter/lib/mobile/presentation/bottom_sheet/bottom_sheet_view_page.dart @@ -1,10 +1,14 @@ import 'package:appflowy/generated/flowy_svgs.g.dart'; import 'package:appflowy/generated/locale_keys.g.dart'; +import 'package:appflowy/mobile/application/base/mobile_view_page_bloc.dart'; import 'package:appflowy/mobile/presentation/bottom_sheet/bottom_sheet.dart'; import 'package:appflowy/mobile/presentation/widgets/flowy_mobile_quick_action_button.dart'; +import 'package:appflowy/plugins/shared/share/share_bloc.dart'; import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart'; +import 'package:appflowy_backend/protobuf/flowy-user/protobuf.dart'; import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; enum MobileViewBottomSheetBodyAction { undo, @@ -15,7 +19,11 @@ enum MobileViewBottomSheetBodyAction { delete, addToFavorites, removeFromFavorites, - helpCenter; + helpCenter, + publish, + unpublish, + copyPublishLink, + visitSite, } typedef MobileViewBottomSheetBodyActionCallback = void Function( @@ -115,6 +123,8 @@ class MobileViewBottomSheetBody extends StatelessWidget { ), ), _divider(), + ..._buildPublishActions(context), + _divider(), MobileQuickActionButton( text: LocaleKeys.button_delete.tr(), textColor: Theme.of(context).colorScheme.error, @@ -129,6 +139,53 @@ class MobileViewBottomSheetBody extends StatelessWidget { ); } + List _buildPublishActions(BuildContext context) { + final userProfile = context.read().state.userProfilePB; + // the publish feature is only available for AppFlowy Cloud + if (userProfile == null || + userProfile.authenticator != AuthenticatorPB.AppFlowyCloud) { + return []; + } + + final isPublished = context.watch().state.isPublished; + if (isPublished) { + return [ + // MobileQuickActionButton( + // text: LocaleKeys.shareAction_copyLink.tr(), + // icon: FlowySvgs.copy_s, + // onTap: () => onAction( + // MobileViewBottomSheetBodyAction.copyPublishLink, + // ), + // ), + MobileQuickActionButton( + text: LocaleKeys.shareAction_visitSite.tr(), + icon: FlowySvgs.copy_s, + onTap: () => onAction( + MobileViewBottomSheetBodyAction.visitSite, + ), + ), + _divider(), + MobileQuickActionButton( + text: LocaleKeys.shareAction_unPublish.tr(), + icon: FlowySvgs.share_publish_s, + onTap: () => onAction( + MobileViewBottomSheetBodyAction.unpublish, + ), + ), + ]; + } else { + return [ + MobileQuickActionButton( + text: LocaleKeys.shareAction_publish.tr(), + icon: FlowySvgs.share_publish_s, + onTap: () => onAction( + MobileViewBottomSheetBodyAction.publish, + ), + ), + ]; + } + } + Widget _divider() => const Divider( height: 8.5, thickness: 0.5, From ddfd83afd1e2f9184780a281c458718e9f48af22 Mon Sep 17 00:00:00 2001 From: "Lucas.Xu" Date: Wed, 18 Sep 2024 17:58:02 +0800 Subject: [PATCH 2/2] chore: replace icons --- .../presentation/bottom_sheet/bottom_sheet_view_page.dart | 3 ++- .../widgets/flowy_mobile_quick_action_button.dart | 7 +++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/frontend/appflowy_flutter/lib/mobile/presentation/bottom_sheet/bottom_sheet_view_page.dart b/frontend/appflowy_flutter/lib/mobile/presentation/bottom_sheet/bottom_sheet_view_page.dart index 0b5b0659df99..85d7b96fba80 100644 --- a/frontend/appflowy_flutter/lib/mobile/presentation/bottom_sheet/bottom_sheet_view_page.dart +++ b/frontend/appflowy_flutter/lib/mobile/presentation/bottom_sheet/bottom_sheet_view_page.dart @@ -159,7 +159,8 @@ class MobileViewBottomSheetBody extends StatelessWidget { // ), MobileQuickActionButton( text: LocaleKeys.shareAction_visitSite.tr(), - icon: FlowySvgs.copy_s, + icon: FlowySvgs.share_s, + iconSize: const Size.square(20), onTap: () => onAction( MobileViewBottomSheetBodyAction.visitSite, ), diff --git a/frontend/appflowy_flutter/lib/mobile/presentation/widgets/flowy_mobile_quick_action_button.dart b/frontend/appflowy_flutter/lib/mobile/presentation/widgets/flowy_mobile_quick_action_button.dart index 5be3d3e78c61..5efa85ff72ab 100644 --- a/frontend/appflowy_flutter/lib/mobile/presentation/widgets/flowy_mobile_quick_action_button.dart +++ b/frontend/appflowy_flutter/lib/mobile/presentation/widgets/flowy_mobile_quick_action_button.dart @@ -10,6 +10,7 @@ class MobileQuickActionButton extends StatelessWidget { required this.text, this.textColor, this.iconColor, + this.iconSize, this.enable = true, }); @@ -18,10 +19,12 @@ class MobileQuickActionButton extends StatelessWidget { final String text; final Color? textColor; final Color? iconColor; + final Size? iconSize; final bool enable; @override Widget build(BuildContext context) { + final iconSize = this.iconSize ?? const Size.square(18); return Padding( padding: const EdgeInsets.symmetric(horizontal: 4), child: InkWell( @@ -37,10 +40,10 @@ class MobileQuickActionButton extends StatelessWidget { children: [ FlowySvg( icon, - size: const Size.square(18), + size: iconSize, color: enable ? iconColor : Theme.of(context).disabledColor, ), - const HSpace(12), + HSpace(30 - iconSize.width), Expanded( child: FlowyText.regular( text,