From 2debd0283c63a195a93d3d15301affc173c4be3c Mon Sep 17 00:00:00 2001 From: Annie Date: Sun, 11 Aug 2024 15:02:29 +0800 Subject: [PATCH] chore: revamp question bubble (#5923) --- .../grid/presentation/widgets/row/action.dart | 2 +- .../tab_bar/desktop/tab_bar_header.dart | 5 + .../widgets/float_bubble/question_bubble.dart | 113 +++++------------- .../float_bubble/social_media_section.dart | 105 ++++++++++++++++ .../widgets/float_bubble/version_section.dart | 73 +++++++++++ .../presentation/widgets/pop_up_action.dart | 7 ++ frontend/resources/flowy_icons/16x/copy.svg | 4 +- frontend/resources/flowy_icons/16x/debug.svg | 20 ++++ .../resources/flowy_icons/16x/help_center.svg | 15 +-- .../resources/flowy_icons/16x/keyboard.svg | 14 +++ .../flowy_icons/16x/message_support.svg | 12 ++ .../flowy_icons/16x/share_feedback.svg | 12 ++ frontend/resources/flowy_icons/16x/star.svg | 10 ++ frontend/resources/translations/en.json | 9 +- 14 files changed, 297 insertions(+), 104 deletions(-) create mode 100644 frontend/appflowy_flutter/lib/workspace/presentation/widgets/float_bubble/social_media_section.dart create mode 100644 frontend/appflowy_flutter/lib/workspace/presentation/widgets/float_bubble/version_section.dart create mode 100644 frontend/resources/flowy_icons/16x/debug.svg create mode 100644 frontend/resources/flowy_icons/16x/keyboard.svg create mode 100644 frontend/resources/flowy_icons/16x/message_support.svg create mode 100644 frontend/resources/flowy_icons/16x/share_feedback.svg create mode 100644 frontend/resources/flowy_icons/16x/star.svg diff --git a/frontend/appflowy_flutter/lib/plugins/database/grid/presentation/widgets/row/action.dart b/frontend/appflowy_flutter/lib/plugins/database/grid/presentation/widgets/row/action.dart index f2c2540764..71b20161b1 100644 --- a/frontend/appflowy_flutter/lib/plugins/database/grid/presentation/widgets/row/action.dart +++ b/frontend/appflowy_flutter/lib/plugins/database/grid/presentation/widgets/row/action.dart @@ -86,7 +86,7 @@ enum RowAction { return switch (this) { insertAbove => FlowySvgs.arrow_s, insertBelow => FlowySvgs.add_s, - duplicate => FlowySvgs.copy_s, + duplicate => FlowySvgs.duplicate_s, delete => FlowySvgs.delete_s, }; } diff --git a/frontend/appflowy_flutter/lib/plugins/database/tab_bar/desktop/tab_bar_header.dart b/frontend/appflowy_flutter/lib/plugins/database/tab_bar/desktop/tab_bar_header.dart index ef7942ec55..6fc3b6d85d 100644 --- a/frontend/appflowy_flutter/lib/plugins/database/tab_bar/desktop/tab_bar_header.dart +++ b/frontend/appflowy_flutter/lib/plugins/database/tab_bar/desktop/tab_bar_header.dart @@ -291,4 +291,9 @@ enum TabBarViewAction implements ActionCell { @override Widget? rightIcon(Color iconColor) => null; + + @override + Color? textColor(BuildContext context) { + return null; + } } diff --git a/frontend/appflowy_flutter/lib/workspace/presentation/widgets/float_bubble/question_bubble.dart b/frontend/appflowy_flutter/lib/workspace/presentation/widgets/float_bubble/question_bubble.dart index 0f7a5d0623..d666e606f6 100644 --- a/frontend/appflowy_flutter/lib/workspace/presentation/widgets/float_bubble/question_bubble.dart +++ b/frontend/appflowy_flutter/lib/workspace/presentation/widgets/float_bubble/question_bubble.dart @@ -1,24 +1,18 @@ import 'package:appflowy/core/helpers/url_launcher.dart'; -import 'package:appflowy/env/env.dart'; import 'package:appflowy/generated/flowy_svgs.g.dart'; import 'package:appflowy/generated/locale_keys.g.dart'; -import 'package:appflowy/plugins/document/application/document_bloc.dart'; import 'package:appflowy/startup/tasks/rust_sdk.dart'; import 'package:appflowy/util/theme_extension.dart'; import 'package:appflowy/workspace/presentation/home/toast.dart'; -import 'package:appflowy/workspace/presentation/widgets/dialogs.dart'; +import 'package:appflowy/workspace/presentation/widgets/float_bubble/social_media_section.dart'; +import 'package:appflowy/workspace/presentation/widgets/float_bubble/version_section.dart'; import 'package:appflowy/workspace/presentation/widgets/pop_up_action.dart'; import 'package:appflowy_popover/appflowy_popover.dart'; import 'package:device_info_plus/device_info_plus.dart'; import 'package:easy_localization/easy_localization.dart'; -import 'package:flowy_infra_ui/style_widget/text.dart'; import 'package:flowy_infra_ui/widget/flowy_tooltip.dart'; -import 'package:flowy_infra_ui/widget/spacing.dart'; -import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; -import 'package:package_info_plus/package_info_plus.dart'; -import 'package:styled_widget/styled_widget.dart'; class QuestionBubble extends StatelessWidget { const QuestionBubble({super.key}); @@ -26,7 +20,7 @@ class QuestionBubble extends StatelessWidget { @override Widget build(BuildContext context) { return const SizedBox.square( - dimension: 36.0, + dimension: 32.0, child: BubbleActionList(), ); } @@ -62,7 +56,9 @@ class _BubbleActionListState extends State { actions.addAll( BubbleAction.values.map((action) => BubbleActionWrapper(action)), ); - actions.add(FlowyVersionDescription()); + + actions.add(SocialMediaSection()); + actions.add(FlowyVersionSection()); final (color, borderColor, shadowColor, iconColor) = Theme.of(context).isLightMode @@ -83,6 +79,11 @@ class _BubbleActionListState extends State { direction: PopoverDirection.topWithRightAligned, actions: actions, offset: const Offset(0, -8), + constraints: const BoxConstraints( + minWidth: 200, + maxWidth: 460, + maxHeight: 400, + ), buildChild: (controller) { return FlowyTooltip( message: LocaleKeys.questionBubble_help.tr(), @@ -90,7 +91,7 @@ class _BubbleActionListState extends State { cursor: SystemMouseCursors.click, child: GestureDetector( child: Container( - padding: const EdgeInsets.all(10.0), + padding: const EdgeInsets.all(8.0), decoration: ShapeDecoration( color: color, shape: RoundedRectangleBorder( @@ -178,75 +179,21 @@ class _DebugToast { } } -class FlowyVersionDescription extends CustomActionCell { - @override - Widget buildWithContext(BuildContext context, PopoverController controller) { - return FutureBuilder( - future: PackageInfo.fromPlatform(), - builder: (BuildContext context, AsyncSnapshot snapshot) { - if (snapshot.connectionState == ConnectionState.done) { - if (snapshot.hasError) { - return FlowyText( - "Error: ${snapshot.error}", - color: Theme.of(context).disabledColor, - ); - } - - final PackageInfo packageInfo = snapshot.data; - final String appName = packageInfo.appName; - final String version = packageInfo.version; - - return SizedBox( - height: 30, - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Divider( - height: 1, - color: Theme.of(context).dividerColor, - thickness: 1.0, - ), - const VSpace(6), - GestureDetector( - behavior: HitTestBehavior.opaque, - onDoubleTap: () { - if (Env.internalBuild != '1' && !kDebugMode) { - return; - } - enableDocumentInternalLog = !enableDocumentInternalLog; - showToastNotification( - context, - message: enableDocumentInternalLog - ? 'Enabled Internal Log' - : 'Disabled Internal Log', - ); - }, - child: FlowyText( - '$appName $version', - color: Theme.of(context).hintColor, - ), - ), - ], - ).padding( - horizontal: ActionListSizes.itemHPadding, - ), - ); - } else { - return const SizedBox(height: 30); - } - }, - ); - } +enum BubbleAction { + whatsNews, + help, + debug, + shortcuts, + markdown, + github, } -enum BubbleAction { whatsNews, help, debug, shortcuts, markdown, github } - class BubbleActionWrapper extends ActionCell { BubbleActionWrapper(this.inner); final BubbleAction inner; @override - Widget? leftIcon(Color iconColor) => inner.emoji; + Widget? leftIcon(Color iconColor) => inner.icons; @override String get name => inner.name; @@ -270,26 +217,20 @@ extension QuestionBubbleExtension on BubbleAction { } } - Widget get emoji { + Widget? get icons { switch (this) { case BubbleAction.whatsNews: - return const FlowyText.regular('🆕'); + return const FlowySvg(FlowySvgs.star_s); case BubbleAction.help: - return const FlowyText.regular('👥'); + return const FlowySvg(FlowySvgs.message_support_s); case BubbleAction.debug: - return const FlowyText.regular('🐛'); + return const FlowySvg(FlowySvgs.debug_s); case BubbleAction.shortcuts: - return const FlowyText.regular('📋'); + return const FlowySvg(FlowySvgs.keyboard_s); case BubbleAction.markdown: - return const FlowyText.regular('✨'); + return const FlowySvg(FlowySvgs.number_s); case BubbleAction.github: - return const Padding( - padding: EdgeInsets.all(3.0), - child: FlowySvg( - FlowySvgs.archive_m, - size: Size.square(12), - ), - ); + return const FlowySvg(FlowySvgs.share_feedback_s); } } } diff --git a/frontend/appflowy_flutter/lib/workspace/presentation/widgets/float_bubble/social_media_section.dart b/frontend/appflowy_flutter/lib/workspace/presentation/widgets/float_bubble/social_media_section.dart new file mode 100644 index 0000000000..dd7c17e7ac --- /dev/null +++ b/frontend/appflowy_flutter/lib/workspace/presentation/widgets/float_bubble/social_media_section.dart @@ -0,0 +1,105 @@ +import 'package:appflowy/core/helpers/url_launcher.dart'; +import 'package:appflowy/workspace/presentation/widgets/pop_up_action.dart'; +import 'package:appflowy_popover/appflowy_popover.dart'; +import 'package:flutter/material.dart'; + +class SocialMediaSection extends CustomActionCell { + @override + Widget buildWithContext(BuildContext context, PopoverController controller) { + final List children = [ + Divider( + height: 1, + color: Theme.of(context).dividerColor, + thickness: 1.0, + ), + ]; + + children.addAll( + SocialMedia.values.map( + (social) { + return ActionCellWidget( + action: SocialMediaWrapper(social), + itemHeight: ActionListSizes.itemHeight, + onSelected: (action) { + switch (action.inner) { + case SocialMedia.reddit: + afLaunchUrlString( + 'https://www.reddit.com/r/AppFlowy/', + ); + case SocialMedia.twitter: + afLaunchUrlString( + 'https://x.com/appflowy', + ); + case SocialMedia.forum: + afLaunchUrlString('https://forum.appflowy.io/'); + } + }, + ); + }, + ), + ); + + return Padding( + padding: const EdgeInsets.symmetric(vertical: 6), + child: Column( + children: children, + ), + ); + } +} + +enum SocialMedia { forum, twitter, reddit } + +class SocialMediaWrapper extends ActionCell { + SocialMediaWrapper(this.inner); + + final SocialMedia inner; + @override + Widget? leftIcon(Color iconColor) => inner.icons; + + @override + String get name => inner.name; + + @override + Color? textColor(BuildContext context) => inner.textColor(context); +} + +extension QuestionBubbleExtension on SocialMedia { + Color? textColor(BuildContext context) { + switch (this) { + case SocialMedia.reddit: + return Theme.of(context).hintColor; + + case SocialMedia.twitter: + return Theme.of(context).hintColor; + + case SocialMedia.forum: + return Theme.of(context).hintColor; + + default: + return null; + } + } + + String get name { + switch (this) { + case SocialMedia.forum: + return "Community Forum"; + case SocialMedia.twitter: + return "Twitter - @appflowy"; + case SocialMedia.reddit: + return "Reddit - r/appflowy"; + } + } + + Widget? get icons { + switch (this) { + case SocialMedia.reddit: + return null; + case SocialMedia.twitter: + return null; + case SocialMedia.forum: + return null; + } + } +} diff --git a/frontend/appflowy_flutter/lib/workspace/presentation/widgets/float_bubble/version_section.dart b/frontend/appflowy_flutter/lib/workspace/presentation/widgets/float_bubble/version_section.dart new file mode 100644 index 0000000000..6363ee08e5 --- /dev/null +++ b/frontend/appflowy_flutter/lib/workspace/presentation/widgets/float_bubble/version_section.dart @@ -0,0 +1,73 @@ +import 'package:appflowy/env/env.dart'; +import 'package:appflowy/plugins/document/application/document_bloc.dart'; +import 'package:appflowy/workspace/presentation/widgets/dialogs.dart'; +import 'package:appflowy/workspace/presentation/widgets/pop_up_action.dart'; +import 'package:appflowy_popover/appflowy_popover.dart'; +import 'package:flowy_infra_ui/style_widget/text.dart'; +import 'package:flowy_infra_ui/widget/spacing.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:package_info_plus/package_info_plus.dart'; +import 'package:styled_widget/styled_widget.dart'; + +class FlowyVersionSection extends CustomActionCell { + @override + Widget buildWithContext(BuildContext context, PopoverController controller) { + return FutureBuilder( + future: PackageInfo.fromPlatform(), + builder: (BuildContext context, AsyncSnapshot snapshot) { + if (snapshot.connectionState == ConnectionState.done) { + if (snapshot.hasError) { + return FlowyText( + "Error: ${snapshot.error}", + color: Theme.of(context).disabledColor, + ); + } + + final PackageInfo packageInfo = snapshot.data; + final String appName = packageInfo.appName; + final String version = packageInfo.version; + + return SizedBox( + height: 30, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Divider( + height: 1, + color: Theme.of(context).dividerColor, + thickness: 1.0, + ), + const VSpace(6), + GestureDetector( + behavior: HitTestBehavior.opaque, + onDoubleTap: () { + if (Env.internalBuild != '1' && !kDebugMode) { + return; + } + enableDocumentInternalLog = !enableDocumentInternalLog; + showToastNotification( + context, + message: enableDocumentInternalLog + ? 'Enabled Internal Log' + : 'Disabled Internal Log', + ); + }, + child: FlowyText( + '$appName $version', + color: Theme.of(context).hintColor, + fontSize: 12, + ).padding( + horizontal: ActionListSizes.itemHPadding, + ), + ), + ], + ), + ); + } else { + return const SizedBox(height: 30); + } + }, + ); + } +} diff --git a/frontend/appflowy_flutter/lib/workspace/presentation/widgets/pop_up_action.dart b/frontend/appflowy_flutter/lib/workspace/presentation/widgets/pop_up_action.dart index 17f78cb8cf..5ce8ee88df 100644 --- a/frontend/appflowy_flutter/lib/workspace/presentation/widgets/pop_up_action.dart +++ b/frontend/appflowy_flutter/lib/workspace/presentation/widgets/pop_up_action.dart @@ -103,6 +103,9 @@ abstract class ActionCell extends PopoverAction { Widget? leftIcon(Color iconColor) => null; Widget? rightIcon(Color iconColor) => null; String get name; + Color? textColor(BuildContext context) { + return null; + } } typedef PopoverActionCellBuilder = Widget Function( @@ -158,6 +161,7 @@ class ActionCellWidget extends StatelessWidget { leftIcon: leftIcon, rightIcon: rightIcon, name: actionCell.name, + textColor: actionCell.textColor(context), onTap: () => onSelected(action), ); } @@ -221,6 +225,7 @@ class HoverButton extends StatelessWidget { this.leftIcon, required this.name, this.rightIcon, + this.textColor, }); final VoidCallback onTap; @@ -228,6 +233,7 @@ class HoverButton extends StatelessWidget { final Widget? leftIcon; final Widget? rightIcon; final String name; + final Color? textColor; @override Widget build(BuildContext context) { @@ -248,6 +254,7 @@ class HoverButton extends StatelessWidget { name, overflow: TextOverflow.visible, lineHeight: 1.15, + color: textColor, ), ), if (rightIcon != null) ...[ diff --git a/frontend/resources/flowy_icons/16x/copy.svg b/frontend/resources/flowy_icons/16x/copy.svg index f11048fd2f..8830822589 100644 --- a/frontend/resources/flowy_icons/16x/copy.svg +++ b/frontend/resources/flowy_icons/16x/copy.svg @@ -1,4 +1,4 @@ - - + + diff --git a/frontend/resources/flowy_icons/16x/debug.svg b/frontend/resources/flowy_icons/16x/debug.svg new file mode 100644 index 0000000000..643edfbd23 --- /dev/null +++ b/frontend/resources/flowy_icons/16x/debug.svg @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/resources/flowy_icons/16x/help_center.svg b/frontend/resources/flowy_icons/16x/help_center.svg index 52766922e9..7840906683 100644 --- a/frontend/resources/flowy_icons/16x/help_center.svg +++ b/frontend/resources/flowy_icons/16x/help_center.svg @@ -1,11 +1,6 @@ - - - - - - - - - - + + + + + diff --git a/frontend/resources/flowy_icons/16x/keyboard.svg b/frontend/resources/flowy_icons/16x/keyboard.svg new file mode 100644 index 0000000000..40cb2d42a8 --- /dev/null +++ b/frontend/resources/flowy_icons/16x/keyboard.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/frontend/resources/flowy_icons/16x/message_support.svg b/frontend/resources/flowy_icons/16x/message_support.svg new file mode 100644 index 0000000000..03e72384d7 --- /dev/null +++ b/frontend/resources/flowy_icons/16x/message_support.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/frontend/resources/flowy_icons/16x/share_feedback.svg b/frontend/resources/flowy_icons/16x/share_feedback.svg new file mode 100644 index 0000000000..9dc9b7f404 --- /dev/null +++ b/frontend/resources/flowy_icons/16x/share_feedback.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/frontend/resources/flowy_icons/16x/star.svg b/frontend/resources/flowy_icons/16x/star.svg new file mode 100644 index 0000000000..f4d6f7ae3c --- /dev/null +++ b/frontend/resources/flowy_icons/16x/star.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/frontend/resources/translations/en.json b/frontend/resources/translations/en.json index 3503b7318f..d0e8a41b89 100644 --- a/frontend/resources/translations/en.json +++ b/frontend/resources/translations/en.json @@ -1498,7 +1498,6 @@ "outline": "Outline", "codeBlock": "Code Block" }, - "plugins": { "referencedBoard": "Referenced Board", "referencedGrid": "Referenced Grid", @@ -1650,12 +1649,12 @@ "file": { "name": "File", "uploadTab": "Upload", - "networkTab": "Integrate link", + "networkTab": "Embed link", "placeholderText": "Click or drag and drop to upload a file", "placeholderDragging": "Drop the file to upload", "dropFileToUpload": "Drop the file to upload", "fileUploadHint": "Drag and drop a file here\nor click to select a file.", - "networkHint": "Enter a link to a file", + "networkHint": "Paste a file link", "networkUrlInvalid": "Invalid URL, please correct the URL and try again", "networkAction": "Embed file link", "fileTooBigError": "File size is too big, please upload a file with size less than 10MB", @@ -1743,7 +1742,7 @@ "placeholder": "Select language", "auto": "Auto" }, - "copyTooltip": "Copy contents of the code block", + "copyTooltip": "Copy", "searchLanguageHint": "Search for a language", "codeCopiedSnackbar": "Code copied to clipboard!" }, @@ -2411,4 +2410,4 @@ "commentAddedSuccessfully": "Comment added successfully.", "commentAddedSuccessTip": "You've just added or replied to a comment. Would you like to jump to the top to see the latest comments?" } -} +} \ No newline at end of file