Skip to content

Commit

Permalink
fix: icon picker issues on mobile (#7114)
Browse files Browse the repository at this point in the history
* fix: icon picker issues on mobile (#7113)

* fix: error displaying in Page style

* fix: error displaying in Favorite/Recent page

* fix: complete the filter logic of icon picker

* fix: the color picker showed when tapping down

* fix: icons are not supported in subpage blocks

* chore: add some tests

* fix: recent icons not working for grid header icon

* fix: recent icon doesn't work in space icon (#7133)

---------

Co-authored-by: Lucas.Xu <[email protected]>
  • Loading branch information
asjqkkkk and LucasXu0 committed Jan 7, 2025
1 parent 1d1647d commit 776f70a
Show file tree
Hide file tree
Showing 20 changed files with 344 additions and 96 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import 'data_migration/data_migration_test_runner.dart'
as data_migration_test_runner;
import 'document/document_test_runner.dart' as document_test_runner;
import 'set_env.dart' as preset_af_cloud_env_test;
import 'sidebar/sidebar_icon_test.dart' as sidebar_icon_test;
import 'sidebar/sidebar_move_page_test.dart' as sidebar_move_page_test;
import 'sidebar/sidebar_rename_untitled_test.dart'
as sidebar_rename_untitled_test;
Expand All @@ -26,4 +27,5 @@ Future<void> main() async {
// sidebar
sidebar_move_page_test.main();
sidebar_rename_untitled_test.main();
sidebar_icon_test.main();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import 'dart:convert';

import 'package:appflowy/env/cloud_env.dart';
import 'package:appflowy/shared/icon_emoji_picker/flowy_icon_emoji_picker.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/menu/sidebar/space/sidebar_space_header.dart';
import 'package:appflowy/workspace/presentation/home/menu/sidebar/space/space_action_type.dart';
import 'package:appflowy/workspace/presentation/home/menu/sidebar/space/space_more_popup.dart';
import 'package:flowy_svg/flowy_svg.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';

import '../../../shared/emoji.dart';
import '../../../shared/util.dart';

void main() {
setUpAll(() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
RecentIcons.enable = false;
});

tearDownAll(() {
RecentIcons.enable = true;
});

testWidgets('Change slide bar space icon', (tester) async {
await tester.initializeAppFlowy(
cloudType: AuthenticatorType.appflowyCloudSelfHost,
);
await tester.tapGoogleLoginInButton();
await tester.expectToSeeHomePageWithGetStartedPage();
final emojiIconData = await tester.loadIcon();
final firstIcon = IconsData.fromJson(jsonDecode(emojiIconData.emoji));

await tester.hoverOnWidget(
find.byType(SidebarSpaceHeader),
onHover: () async {
final moreOption = find.byType(SpaceMorePopup);
await tester.tapButton(moreOption);
expect(find.byType(FlowyIconEmojiPicker), findsNothing);
await tester.tapSvgButton(SpaceMoreActionType.changeIcon.leftIconSvg);
expect(find.byType(FlowyIconEmojiPicker), findsOneWidget);
},
);

final icons = find.byWidgetPredicate(
(w) => w is FlowySvg && w.svgString == firstIcon.iconContent,
);
expect(icons, findsOneWidget);
await tester.tapIcon(EmojiIconData.icon(firstIcon));

final spaceHeader = find.byType(SidebarSpaceHeader);
final spaceIcon = find.descendant(
of: spaceHeader,
matching: find.byWidgetPredicate(
(w) => w is FlowySvg && w.svgString == firstIcon.iconContent,
),
);
expect(spaceIcon, findsOneWidget);
});
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import 'dart:io';

import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/header/emoji_icon_widget.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/sub_page/sub_page_block_component.dart';
import 'package:appflowy/shared/icon_emoji_picker/recent_icons.dart';
import 'package:appflowy/workspace/presentation/home/menu/view/view_action_type.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
import 'package:appflowy_editor/appflowy_editor.dart';
Expand All @@ -11,6 +13,7 @@ import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';

import '../../shared/emoji.dart';
import '../../shared/util.dart';

// Test cases for the Document SubPageBlock that needs to be covered:
Expand All @@ -37,7 +40,14 @@ import '../../shared/util.dart';
const _defaultPageName = "";

void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
setUpAll(() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
RecentIcons.enable = false;
});

tearDownAll(() {
RecentIcons.enable = true;
});

group('Document SubPageBlock tests', () {
testWidgets('Insert a new SubPageBlock from Slash menu items',
Expand Down Expand Up @@ -498,6 +508,38 @@ void main() {

expect(find.text('Parent'), findsNWidgets(2));
});

testWidgets('Displaying icon of subpage', (tester) async {
const firstPage = 'FirstPage';

await tester.initializeAppFlowy();
await tester.tapAnonymousSignInButton();
await tester.createNewPageWithNameUnderParent(name: firstPage);
final icon = await tester.loadIcon();

/// create subpage
await tester.editor.tapLineOfEditorAt(0);
await tester.editor.showSlashMenu();
await tester.editor.tapSlashMenuItemWithName(
LocaleKeys.document_slashMenu_subPage_name.tr(),
offset: 100,
);

/// add icon
await tester.editor.hoverOnCoverToolbar();
await tester.editor.tapAddIconButton();
await tester.tapIcon(icon);
await tester.pumpAndSettle();
await tester.openPage(firstPage);

/// check if there is a icon in document
final iconWidget = find.byWidgetPredicate((w) {
if (w is! RawEmojiIconWidget) return false;
final iconData = w.emoji.emoji;
return iconData == icon.emoji;
});
expect(iconWidget, findsOneWidget);
});
});
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import 'package:appflowy/plugins/base/emoji/emoji_picker.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/base/emoji_picker_button.dart';
import 'package:appflowy/shared/icon_emoji_picker/flowy_icon_emoji_picker.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/menu/sidebar/space/space_icon_popup.dart';
import 'package:appflowy/workspace/presentation/widgets/view_title_bar.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
import 'package:flowy_infra_ui/style_widget/text_field.dart';
Expand All @@ -27,21 +25,6 @@ void main() {
RecentIcons.enable = true;
});

Future<EmojiIconData> loadIcon() async {
await loadIconGroups();
final groups = kIconGroups!;
final firstGroup = groups.first;
final firstIcon = firstGroup.icons.first;
return EmojiIconData.icon(
IconsData(
firstGroup.name,
firstIcon.content,
firstIcon.name,
builtInSpaceColors.first,
),
);
}

testWidgets('Update page emoji in sidebar', (tester) async {
await tester.initializeAppFlowy();
await tester.tapAnonymousSignInButton();
Expand Down Expand Up @@ -160,7 +143,7 @@ void main() {
testWidgets('Update page icon in sidebar', (tester) async {
await tester.initializeAppFlowy();
await tester.tapAnonymousSignInButton();
final iconData = await loadIcon();
final iconData = await tester.loadIcon();

// create document, board, grid and calendar views
for (final value in ViewLayoutPB.values) {
Expand Down Expand Up @@ -192,7 +175,7 @@ void main() {
testWidgets('Update page icon in title bar', (tester) async {
await tester.initializeAppFlowy();
await tester.tapAnonymousSignInButton();
final iconData = await loadIcon();
final iconData = await tester.loadIcon();

// create document, board, grid and calendar views
for (final value in ViewLayoutPB.values) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,30 @@
import 'package:appflowy/generated/flowy_svgs.g.dart';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/mobile/application/page_style/document_page_style_bloc.dart';
import 'package:appflowy/mobile/presentation/base/view_page/app_bar_buttons.dart';
import 'package:appflowy/mobile/presentation/bottom_sheet/bottom_sheet_buttons.dart';
import 'package:appflowy/mobile/presentation/mobile_bottom_navigation_bar.dart';
import 'package:appflowy/plugins/document/presentation/editor_page.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/cover/document_immersive_cover.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/page_style/_page_style_icon.dart';
import 'package:appflowy/shared/icon_emoji_picker/recent_icons.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';

import '../../shared/emoji.dart';
import '../../shared/util.dart';

void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
setUpAll(() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
RecentIcons.enable = false;
});

tearDownAll(() {
RecentIcons.enable = true;
});

group('document page style:', () {
double getCurrentEditorFontSize() {
Expand Down Expand Up @@ -114,5 +127,37 @@ void main() {
);
expect(builtInCover, findsOneWidget);
});

testWidgets('page style icon', (tester) async {
await tester.launchInAnonymousMode();

final createPageButton =
find.byKey(BottomNavigationBarItemType.add.valueKey);
await tester.tapButton(createPageButton);

/// toggle the preset button
await tester.tapSvgButton(FlowySvgs.m_layout_s);

/// select document plugins emoji
final pageStyleIcon = find.byType(PageStyleIcon);

/// there should be none of emoji
final noneText = find.text(LocaleKeys.pageStyle_none.tr());
expect(noneText, findsOneWidget);
await tester.tapButton(pageStyleIcon);

/// select an emoji
const emoji = '😄';
await tester.tapEmoji(emoji);
await tester.tapSvgButton(FlowySvgs.m_layout_s);
expect(noneText, findsNothing);
expect(
find.descendant(
of: pageStyleIcon,
matching: find.text(emoji),
),
findsOneWidget,
);
});
});
}
27 changes: 27 additions & 0 deletions frontend/appflowy_flutter/integration_test/shared/base.dart
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,33 @@ extension AppFlowyTestBase on WidgetTester {
}
}

Future<void> tapDown(
Finder finder, {
int? pointer,
int buttons = kPrimaryButton,
PointerDeviceKind kind = PointerDeviceKind.touch,
bool pumpAndSettle = true,
int milliseconds = 500,
}) async {
final location = getCenter(finder);
final TestGesture gesture = await startGesture(
location,
pointer: pointer,
buttons: buttons,
kind: kind,
);
await gesture.cancel();
await gesture.down(location);
await gesture.cancel();
if (pumpAndSettle) {
await this.pumpAndSettle(
Duration(milliseconds: milliseconds),
EnginePhase.sendSemanticsUpdate,
const Duration(seconds: 15),
);
}
}

Future<void> tapButtonWithName(
String tr, {
int milliseconds = 500,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import 'package:appflowy/plugins/document/presentation/editor_plugins/simple_tab
import 'package:appflowy/plugins/shared/share/share_button.dart';
import 'package:appflowy/shared/feature_flags.dart';
import 'package:appflowy/shared/icon_emoji_picker/flowy_icon_emoji_picker.dart';
import 'package:appflowy/shared/icon_emoji_picker/icon_picker.dart';
import 'package:appflowy/shared/text_field/text_filed_with_metric_lines.dart';
import 'package:appflowy/startup/startup.dart';
import 'package:appflowy/user/presentation/screens/screens.dart';
Expand All @@ -23,6 +24,7 @@ import 'package:appflowy/workspace/presentation/home/menu/sidebar/shared/sidebar
import 'package:appflowy/workspace/presentation/home/menu/sidebar/space/shared_widget.dart';
import 'package:appflowy/workspace/presentation/home/menu/sidebar/space/sidebar_space_header.dart';
import 'package:appflowy/workspace/presentation/home/menu/sidebar/space/sidebar_space_menu.dart';
import 'package:appflowy/workspace/presentation/home/menu/sidebar/space/space_icon_popup.dart';
import 'package:appflowy/workspace/presentation/home/menu/sidebar/workspace/_sidebar_workspace_menu.dart';
import 'package:appflowy/workspace/presentation/home/menu/sidebar/workspace/sidebar_workspace.dart';
import 'package:appflowy/workspace/presentation/home/menu/view/draggable_view_item.dart';
Expand Down Expand Up @@ -898,6 +900,22 @@ extension CommonOperations on WidgetTester {
await tapAt(Offset.zero);
await pumpUntilNotFound(finder);
}

/// load icon list and return the first one
Future<EmojiIconData> loadIcon() async {
await loadIconGroups();
final groups = kIconGroups!;
final firstGroup = groups.first;
final firstIcon = firstGroup.icons.first;
return EmojiIconData.icon(
IconsData(
firstGroup.name,
firstIcon.content,
firstIcon.name,
builtInSpaceColors.first,
),
);
}
}

extension SettingsFinder on CommonFinders {
Expand Down
10 changes: 6 additions & 4 deletions frontend/appflowy_flutter/integration_test/shared/emoji.dart
Original file line number Diff line number Diff line change
Expand Up @@ -31,17 +31,19 @@ extension EmojiTestExtension on WidgetTester {
matching: find.text(PickerTabType.icon.tr),
);
expect(iconTab, findsOneWidget);
expect(find.byType(FlowyIconPicker), findsNothing);
await tap(iconTab);
await pumpAndSettle();
expect(find.byType(FlowyIconPicker), findsOneWidget);
await tapButton(iconTab);
final selectedSvg = find.descendant(
of: find.byType(FlowyIconPicker),
matching: find.byWidgetPredicate(
(w) => w is FlowySvg && w.svgString == iconsData.iconContent,
),
);
expect(find.byType(IconColorPicker), findsNothing);

/// test for tapping down, it should not display the ColorPicker unless tapping up
await tapDown(selectedSvg);
expect(find.byType(IconColorPicker), findsNothing);

await tapButton(selectedSvg);
final colorPicker = find.byType(IconColorPicker);
expect(colorPicker, findsOneWidget);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -268,8 +268,8 @@ class _MobileViewPageState extends State<MobileViewPage> {
return Row(
mainAxisSize: MainAxisSize.min,
children: [
if (icon != null) ...[
EmojiIconWidget(
if (icon != null && icon.value.isNotEmpty) ...[
RawEmojiIconWidget(
emoji: icon.toEmojiIconData(),
emojiSize: 15,
),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import 'package:appflowy/mobile/presentation/bottom_sheet/bottom_sheet.dart';
import 'package:appflowy/mobile/presentation/home/workspaces/workspace_menu_bottom_sheet.dart';
import 'package:appflowy/plugins/base/emoji/emoji_picker_screen.dart';
import 'package:appflowy/shared/icon_emoji_picker/flowy_icon_emoji_picker.dart';
import 'package:appflowy/shared/icon_emoji_picker/tab.dart';
import 'package:appflowy/startup/startup.dart';
import 'package:appflowy/util/built_in_svgs.dart';
import 'package:appflowy/workspace/application/user/settings_user_bloc.dart';
Expand Down Expand Up @@ -234,6 +235,7 @@ class _UserIcon extends StatelessWidget {
queryParameters: {
MobileEmojiPickerScreen.pageTitle:
LocaleKeys.titleBar_userIcon.tr(),
MobileEmojiPickerScreen.selectTabs: [PickerTabType.emoji.name],
},
).toString(),
);
Expand Down
Loading

0 comments on commit 776f70a

Please sign in to comment.