diff --git a/frontend/appflowy_flutter/integration_test/desktop/uncategorized/tabs_test.dart b/frontend/appflowy_flutter/integration_test/desktop/uncategorized/tabs_test.dart index d0bc391987e66..63ec958c54b9f 100644 --- a/frontend/appflowy_flutter/integration_test/desktop/uncategorized/tabs_test.dart +++ b/frontend/appflowy_flutter/integration_test/desktop/uncategorized/tabs_test.dart @@ -1,11 +1,15 @@ +import 'dart:convert'; import 'dart:io'; import 'package:appflowy/generated/locale_keys.g.dart'; +import 'package:appflowy/shared/icon_emoji_picker/icon_picker.dart'; +import 'package:appflowy/shared/icon_emoji_picker/recent_icons.dart'; import 'package:appflowy/workspace/presentation/home/tabs/flowy_tab.dart'; import 'package:appflowy/workspace/presentation/home/tabs/tabs_manager.dart'; import 'package:appflowy/workspace/presentation/widgets/tab_bar_item.dart'; import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart'; import 'package:easy_localization/easy_localization.dart'; +import 'package:flowy_svg/flowy_svg.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; @@ -285,6 +289,39 @@ void main() { expect(tester.isTabAtIndex(secondTabName, 1), isTrue); expect(tester.isTabAtIndex(thirdTabName, 2), isTrue); }); + + testWidgets('displaying icons in tab', (tester) async { + RecentIcons.enable = false; + await tester.initializeAppFlowy(); + await tester.tapAnonymousSignInButton(); + + final icon = await tester.loadIcon(); + // update emoji + await tester.updatePageIconInSidebarByName( + name: gettingStarted, + parentName: gettingStarted, + layout: ViewLayoutPB.Document, + icon: icon, + ); + + /// create new page + await tester.createNewPageWithNameUnderParent(name: _documentName); + + /// open new tab for [gettingStarted] + await tester.openAppInNewTab(gettingStarted, ViewLayoutPB.Document); + + final tabs = find.descendant( + of: find.byType(TabsManager), + matching: find.byType(FlowyTab), + ); + expect(tabs, findsNWidgets(2)); + + final svgInTab = + find.descendant(of: tabs.last, matching: find.byType(FlowySvg)); + final svgWidget = svgInTab.evaluate().first.widget as FlowySvg; + final iconsData = IconsData.fromJson(jsonDecode(icon.emoji)); + expect(svgWidget.svgString, iconsData.svgString); + }); }); } diff --git a/frontend/appflowy_flutter/integration_test/shared/common_operations.dart b/frontend/appflowy_flutter/integration_test/shared/common_operations.dart index 7c84574737257..f188106f824c4 100644 --- a/frontend/appflowy_flutter/integration_test/shared/common_operations.dart +++ b/frontend/appflowy_flutter/integration_test/shared/common_operations.dart @@ -629,7 +629,7 @@ extension CommonOperations on WidgetTester { // update the page icon in the sidebar Future updatePageIconInSidebarByName({ required String name, - required String parentName, + String? parentName, required ViewLayoutPB layout, required EmojiIconData icon, }) async { diff --git a/frontend/appflowy_flutter/lib/mobile/presentation/home/recent_folder/mobile_recent_view.dart b/frontend/appflowy_flutter/lib/mobile/presentation/home/recent_folder/mobile_recent_view.dart index b60d354ede755..cad05acad4112 100644 --- a/frontend/appflowy_flutter/lib/mobile/presentation/home/recent_folder/mobile_recent_view.dart +++ b/frontend/appflowy_flutter/lib/mobile/presentation/home/recent_folder/mobile_recent_view.dart @@ -3,7 +3,7 @@ import 'dart:io'; import 'package:appflowy/mobile/application/mobile_router.dart'; import 'package:appflowy/mobile/application/page_style/document_page_style_bloc.dart'; import 'package:appflowy/mobile/application/recent/recent_view_bloc.dart'; -import 'package:appflowy/plugins/base/emoji/emoji_text.dart'; +import 'package:appflowy/plugins/document/presentation/editor_plugins/header/emoji_icon_widget.dart'; import 'package:appflowy/plugins/document/presentation/editor_plugins/plugins.dart'; import 'package:appflowy/shared/appflowy_network_image.dart'; import 'package:appflowy/shared/flowy_gradient_colors.dart'; @@ -110,10 +110,7 @@ class MobileRecentView extends StatelessWidget { return Padding( padding: const EdgeInsets.only(left: 8.0), child: state.icon.isNotEmpty - ? EmojiText( - emoji: state.icon.emoji, - fontSize: 30.0, - ) + ? RawEmojiIconWidget(emoji: state.icon, emojiSize: 30) : SizedBox.square( dimension: 32.0, child: view.defaultIcon(), diff --git a/frontend/appflowy_flutter/lib/plugins/database/tab_bar/mobile/mobile_tab_bar_header.dart b/frontend/appflowy_flutter/lib/plugins/database/tab_bar/mobile/mobile_tab_bar_header.dart index 3606ed82a3d34..39fa234b6e6e4 100644 --- a/frontend/appflowy_flutter/lib/plugins/database/tab_bar/mobile/mobile_tab_bar_header.dart +++ b/frontend/appflowy_flutter/lib/plugins/database/tab_bar/mobile/mobile_tab_bar_header.dart @@ -1,10 +1,11 @@ import 'package:appflowy/plugins/database/grid/presentation/layout/sizes.dart'; +import 'package:appflowy/plugins/document/presentation/editor_plugins/header/emoji_icon_widget.dart'; +import 'package:appflowy/shared/icon_emoji_picker/flowy_icon_emoji_picker.dart'; import 'package:flutter/material.dart'; import 'package:appflowy/generated/flowy_svgs.g.dart'; import 'package:appflowy/mobile/presentation/bottom_sheet/show_transition_bottom_sheet.dart'; import 'package:appflowy/mobile/presentation/database/view/database_view_list.dart'; -import 'package:appflowy/plugins/base/emoji/emoji_text.dart'; import 'package:appflowy/plugins/database/application/tab_bar_bloc.dart'; import 'package:appflowy/plugins/database/widgets/setting/mobile_database_controls.dart'; import 'package:appflowy/workspace/application/view/view_bloc.dart'; @@ -143,9 +144,9 @@ class _DatabaseViewSelectorButton extends StatelessWidget { Widget _buildViewIconButton(BuildContext context, ViewPB view) { return view.icon.value.isNotEmpty - ? EmojiText( - emoji: view.icon.value, - fontSize: 16.0, + ? RawEmojiIconWidget( + emoji: view.icon.toEmojiIconData(), + emojiSize: 16.0, ) : SizedBox.square( dimension: 16.0, diff --git a/frontend/appflowy_flutter/lib/plugins/database_document/presentation/database_document_title.dart b/frontend/appflowy_flutter/lib/plugins/database_document/presentation/database_document_title.dart index 7c7a408b17ed5..788834d07441b 100644 --- a/frontend/appflowy_flutter/lib/plugins/database_document/presentation/database_document_title.dart +++ b/frontend/appflowy_flutter/lib/plugins/database_document/presentation/database_document_title.dart @@ -7,6 +7,7 @@ import 'package:appflowy/plugins/database/widgets/cell/editable_cell_skeleton/te import 'package:appflowy/plugins/database/widgets/row/cells/cell_container.dart'; import 'package:appflowy/plugins/document/presentation/editor_plugins/base/emoji_picker_button.dart'; import 'package:appflowy/plugins/document/presentation/editor_plugins/header/emoji_icon_widget.dart'; +import 'package:appflowy/shared/icon_emoji_picker/tab.dart'; import 'package:appflowy/workspace/presentation/widgets/view_title_bar.dart'; import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart'; import 'package:collection/collection.dart'; @@ -173,11 +174,13 @@ class _TitleSkin extends IEditableTextCellSkin { }, onUpdateName: (text) => bloc.add(TextCellEvent.updateText(text)), + tabs: const [PickerTabType.emoji], ); }, child: FlowyButton( useIntrinsicWidth: true, onTap: () {}, + margin: const EdgeInsets.symmetric(horizontal: 6), text: Row( children: [ if (state.icon != null) ...[ @@ -212,6 +215,7 @@ class RenameRowPopover extends StatefulWidget { required this.onUpdateName, required this.onUpdateIcon, required this.icon, + this.tabs = const [PickerTabType.emoji, PickerTabType.icon], }); final TextEditingController textController; @@ -219,6 +223,7 @@ class RenameRowPopover extends StatefulWidget { final ValueChanged onUpdateName; final ValueChanged onUpdateIcon; + final List tabs; @override State createState() => _RenameRowPopoverState(); @@ -248,6 +253,7 @@ class _RenameRowPopoverState extends State { widget.onUpdateIcon(r.data); if (!r.keepOpen) PopoverContainer.of(context).close(); }, + tabs: widget.tabs, ), const HSpace(6), SizedBox( diff --git a/frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/base/emoji_picker_button.dart b/frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/base/emoji_picker_button.dart index 894536dbcca55..c532dd5e521c2 100644 --- a/frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/base/emoji_picker_button.dart +++ b/frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/base/emoji_picker_button.dart @@ -1,6 +1,7 @@ import 'package:appflowy/plugins/base/emoji/emoji_picker_screen.dart'; import 'package:appflowy/plugins/document/presentation/editor_plugins/header/emoji_icon_widget.dart'; import 'package:appflowy/shared/icon_emoji_picker/flowy_icon_emoji_picker.dart'; +import 'package:appflowy/shared/icon_emoji_picker/tab.dart'; import 'package:flowy_infra_ui/flowy_infra_ui.dart'; import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; @@ -21,6 +22,7 @@ class EmojiPickerButton extends StatelessWidget { this.enable = true, this.margin, this.buttonSize, + this.tabs = const [PickerTabType.emoji, PickerTabType.icon], }); final EmojiIconData emoji; @@ -39,6 +41,7 @@ class EmojiPickerButton extends StatelessWidget { final bool enable; final EdgeInsets? margin; final Size? buttonSize; + final List tabs; @override Widget build(BuildContext context) { @@ -55,6 +58,7 @@ class EmojiPickerButton extends StatelessWidget { showBorder: showBorder, enable: enable, buttonSize: buttonSize, + tabs: tabs, ); } @@ -65,6 +69,7 @@ class EmojiPickerButton extends StatelessWidget { enable: enable, title: title, margin: margin, + tabs: tabs, ); } } @@ -82,6 +87,7 @@ class _DesktopEmojiPickerButton extends StatelessWidget { this.showBorder = true, this.enable = true, this.buttonSize, + this.tabs = const [PickerTabType.emoji, PickerTabType.icon], }); final EmojiIconData emoji; @@ -99,6 +105,7 @@ class _DesktopEmojiPickerButton extends StatelessWidget { final bool showBorder; final bool enable; final Size? buttonSize; + final List tabs; @override Widget build(BuildContext context) { @@ -118,6 +125,7 @@ class _DesktopEmojiPickerButton extends StatelessWidget { padding: const EdgeInsets.all(4.0), child: FlowyIconEmojiPicker( initialType: emoji.type.toPickerTabType(), + tabs: tabs, onSelectedEmoji: (r) { onSubmitted(r, popoverController); }, @@ -157,6 +165,7 @@ class _MobileEmojiPickerButton extends StatelessWidget { this.enable = true, this.title, this.margin, + this.tabs = const [PickerTabType.emoji, PickerTabType.icon], }); final EmojiIconData emoji; @@ -168,6 +177,7 @@ class _MobileEmojiPickerButton extends StatelessWidget { final String? title; final bool enable; final EdgeInsets? margin; + final List tabs; @override Widget build(BuildContext context) { @@ -187,6 +197,8 @@ class _MobileEmojiPickerButton extends StatelessWidget { queryParameters: { MobileEmojiPickerScreen.pageTitle: title, MobileEmojiPickerScreen.iconSelectedType: emoji.type.name, + MobileEmojiPickerScreen.selectTabs: + tabs.map((e) => e.name).toList(), }, ).toString(), ); diff --git a/frontend/appflowy_flutter/lib/workspace/presentation/widgets/rename_view_popover.dart b/frontend/appflowy_flutter/lib/workspace/presentation/widgets/rename_view_popover.dart index cae65cafca14e..40c1a91defb26 100644 --- a/frontend/appflowy_flutter/lib/workspace/presentation/widgets/rename_view_popover.dart +++ b/frontend/appflowy_flutter/lib/workspace/presentation/widgets/rename_view_popover.dart @@ -1,4 +1,5 @@ import 'package:appflowy/plugins/document/presentation/editor_plugins/base/emoji_picker_button.dart'; +import 'package:appflowy/shared/icon_emoji_picker/tab.dart'; import 'package:appflowy/workspace/application/view/view_service.dart'; import 'package:appflowy_popover/appflowy_popover.dart'; import 'package:flowy_infra_ui/style_widget/text_field.dart'; @@ -17,6 +18,7 @@ class RenameViewPopover extends StatefulWidget { required this.emoji, this.icon, this.showIconChanger = true, + this.tabs = const [PickerTabType.emoji, PickerTabType.icon], }); final String viewId; @@ -25,6 +27,7 @@ class RenameViewPopover extends StatefulWidget { final EmojiIconData emoji; final Widget? icon; final bool showIconChanger; + final List tabs; @override State createState() => _RenameViewPopoverState(); @@ -61,6 +64,7 @@ class _RenameViewPopoverState extends State { direction: PopoverDirection.bottomWithCenterAligned, offset: const Offset(0, 18), onSubmitted: _updateViewIcon, + tabs: widget.tabs, ), ), const HSpace(6), diff --git a/frontend/appflowy_flutter/lib/workspace/presentation/widgets/tab_bar_item.dart b/frontend/appflowy_flutter/lib/workspace/presentation/widgets/tab_bar_item.dart index 4ce5a93ab02e4..88474b20b356e 100644 --- a/frontend/appflowy_flutter/lib/workspace/presentation/widgets/tab_bar_item.dart +++ b/frontend/appflowy_flutter/lib/workspace/presentation/widgets/tab_bar_item.dart @@ -1,9 +1,10 @@ +import 'package:appflowy/plugins/document/presentation/editor_plugins/header/emoji_icon_widget.dart'; +import 'package:appflowy/shared/icon_emoji_picker/flowy_icon_emoji_picker.dart'; import 'package:appflowy/workspace/application/view/view_ext.dart'; -import 'package:flutter/material.dart'; - import 'package:appflowy/workspace/application/view/view_listener.dart'; import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart'; import 'package:flowy_infra_ui/flowy_infra_ui.dart'; +import 'package:flutter/material.dart'; class ViewTabBarItem extends StatefulWidget { const ViewTabBarItem({ @@ -50,11 +51,9 @@ class _ViewTabBarItemState extends State { widget.shortForm ? MainAxisAlignment.center : MainAxisAlignment.start, children: [ if (widget.view.icon.value.isNotEmpty) - FlowyText.emoji( - widget.view.icon.value, - fontSize: 16.0, - figmaLineHeight: 20.0, - optimizeEmojiAlign: true, + RawEmojiIconWidget( + emoji: widget.view.icon.toEmojiIconData(), + emojiSize: 16, ), if (!widget.shortForm && view.icon.value.isNotEmpty) const HSpace(6), if (!widget.shortForm || view.icon.value.isEmpty) ...[