Skip to content

Commit 27ed2fb

Browse files
asjqkkkkLucasXu0
andauthored
fix: icon picker issues on mobile (#7114)
* 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]>
1 parent b3f94be commit 27ed2fb

File tree

20 files changed

+344
-96
lines changed

20 files changed

+344
-96
lines changed

frontend/appflowy_flutter/integration_test/desktop/cloud/cloud_runner.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import 'data_migration/data_migration_test_runner.dart'
22
as data_migration_test_runner;
33
import 'document/document_test_runner.dart' as document_test_runner;
44
import 'set_env.dart' as preset_af_cloud_env_test;
5+
import 'sidebar/sidebar_icon_test.dart' as sidebar_icon_test;
56
import 'sidebar/sidebar_move_page_test.dart' as sidebar_move_page_test;
67
import 'sidebar/sidebar_rename_untitled_test.dart'
78
as sidebar_rename_untitled_test;
@@ -26,4 +27,5 @@ Future<void> main() async {
2627
// sidebar
2728
sidebar_move_page_test.main();
2829
sidebar_rename_untitled_test.main();
30+
sidebar_icon_test.main();
2931
}
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import 'dart:convert';
2+
3+
import 'package:appflowy/env/cloud_env.dart';
4+
import 'package:appflowy/shared/icon_emoji_picker/flowy_icon_emoji_picker.dart';
5+
import 'package:appflowy/shared/icon_emoji_picker/icon_picker.dart';
6+
import 'package:appflowy/shared/icon_emoji_picker/recent_icons.dart';
7+
import 'package:appflowy/workspace/presentation/home/menu/sidebar/space/sidebar_space_header.dart';
8+
import 'package:appflowy/workspace/presentation/home/menu/sidebar/space/space_action_type.dart';
9+
import 'package:appflowy/workspace/presentation/home/menu/sidebar/space/space_more_popup.dart';
10+
import 'package:flowy_svg/flowy_svg.dart';
11+
import 'package:flutter_test/flutter_test.dart';
12+
import 'package:integration_test/integration_test.dart';
13+
14+
import '../../../shared/emoji.dart';
15+
import '../../../shared/util.dart';
16+
17+
void main() {
18+
setUpAll(() {
19+
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
20+
RecentIcons.enable = false;
21+
});
22+
23+
tearDownAll(() {
24+
RecentIcons.enable = true;
25+
});
26+
27+
testWidgets('Change slide bar space icon', (tester) async {
28+
await tester.initializeAppFlowy(
29+
cloudType: AuthenticatorType.appflowyCloudSelfHost,
30+
);
31+
await tester.tapGoogleLoginInButton();
32+
await tester.expectToSeeHomePageWithGetStartedPage();
33+
final emojiIconData = await tester.loadIcon();
34+
final firstIcon = IconsData.fromJson(jsonDecode(emojiIconData.emoji));
35+
36+
await tester.hoverOnWidget(
37+
find.byType(SidebarSpaceHeader),
38+
onHover: () async {
39+
final moreOption = find.byType(SpaceMorePopup);
40+
await tester.tapButton(moreOption);
41+
expect(find.byType(FlowyIconEmojiPicker), findsNothing);
42+
await tester.tapSvgButton(SpaceMoreActionType.changeIcon.leftIconSvg);
43+
expect(find.byType(FlowyIconEmojiPicker), findsOneWidget);
44+
},
45+
);
46+
47+
final icons = find.byWidgetPredicate(
48+
(w) => w is FlowySvg && w.svgString == firstIcon.iconContent,
49+
);
50+
expect(icons, findsOneWidget);
51+
await tester.tapIcon(EmojiIconData.icon(firstIcon));
52+
53+
final spaceHeader = find.byType(SidebarSpaceHeader);
54+
final spaceIcon = find.descendant(
55+
of: spaceHeader,
56+
matching: find.byWidgetPredicate(
57+
(w) => w is FlowySvg && w.svgString == firstIcon.iconContent,
58+
),
59+
);
60+
expect(spaceIcon, findsOneWidget);
61+
});
62+
}

frontend/appflowy_flutter/integration_test/desktop/document/document_sub_page_test.dart

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
import 'dart:io';
22

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

16+
import '../../shared/emoji.dart';
1417
import '../../shared/util.dart';
1518

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

3942
void main() {
40-
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
43+
setUpAll(() {
44+
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
45+
RecentIcons.enable = false;
46+
});
47+
48+
tearDownAll(() {
49+
RecentIcons.enable = true;
50+
});
4151

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

499509
expect(find.text('Parent'), findsNWidgets(2));
500510
});
511+
512+
testWidgets('Displaying icon of subpage', (tester) async {
513+
const firstPage = 'FirstPage';
514+
515+
await tester.initializeAppFlowy();
516+
await tester.tapAnonymousSignInButton();
517+
await tester.createNewPageWithNameUnderParent(name: firstPage);
518+
final icon = await tester.loadIcon();
519+
520+
/// create subpage
521+
await tester.editor.tapLineOfEditorAt(0);
522+
await tester.editor.showSlashMenu();
523+
await tester.editor.tapSlashMenuItemWithName(
524+
LocaleKeys.document_slashMenu_subPage_name.tr(),
525+
offset: 100,
526+
);
527+
528+
/// add icon
529+
await tester.editor.hoverOnCoverToolbar();
530+
await tester.editor.tapAddIconButton();
531+
await tester.tapIcon(icon);
532+
await tester.pumpAndSettle();
533+
await tester.openPage(firstPage);
534+
535+
/// check if there is a icon in document
536+
final iconWidget = find.byWidgetPredicate((w) {
537+
if (w is! RawEmojiIconWidget) return false;
538+
final iconData = w.emoji.emoji;
539+
return iconData == icon.emoji;
540+
});
541+
expect(iconWidget, findsOneWidget);
542+
});
501543
});
502544
}
503545

frontend/appflowy_flutter/integration_test/desktop/sidebar/sidebar_icon_test.dart

Lines changed: 2 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
import 'package:appflowy/plugins/base/emoji/emoji_picker.dart';
22
import 'package:appflowy/plugins/document/presentation/editor_plugins/base/emoji_picker_button.dart';
33
import 'package:appflowy/shared/icon_emoji_picker/flowy_icon_emoji_picker.dart';
4-
import 'package:appflowy/shared/icon_emoji_picker/icon_picker.dart';
54
import 'package:appflowy/shared/icon_emoji_picker/recent_icons.dart';
6-
import 'package:appflowy/workspace/presentation/home/menu/sidebar/space/space_icon_popup.dart';
75
import 'package:appflowy/workspace/presentation/widgets/view_title_bar.dart';
86
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
97
import 'package:flowy_infra_ui/style_widget/text_field.dart';
@@ -27,21 +25,6 @@ void main() {
2725
RecentIcons.enable = true;
2826
});
2927

30-
Future<EmojiIconData> loadIcon() async {
31-
await loadIconGroups();
32-
final groups = kIconGroups!;
33-
final firstGroup = groups.first;
34-
final firstIcon = firstGroup.icons.first;
35-
return EmojiIconData.icon(
36-
IconsData(
37-
firstGroup.name,
38-
firstIcon.content,
39-
firstIcon.name,
40-
builtInSpaceColors.first,
41-
),
42-
);
43-
}
44-
4528
testWidgets('Update page emoji in sidebar', (tester) async {
4629
await tester.initializeAppFlowy();
4730
await tester.tapAnonymousSignInButton();
@@ -160,7 +143,7 @@ void main() {
160143
testWidgets('Update page icon in sidebar', (tester) async {
161144
await tester.initializeAppFlowy();
162145
await tester.tapAnonymousSignInButton();
163-
final iconData = await loadIcon();
146+
final iconData = await tester.loadIcon();
164147

165148
// create document, board, grid and calendar views
166149
for (final value in ViewLayoutPB.values) {
@@ -192,7 +175,7 @@ void main() {
192175
testWidgets('Update page icon in title bar', (tester) async {
193176
await tester.initializeAppFlowy();
194177
await tester.tapAnonymousSignInButton();
195-
final iconData = await loadIcon();
178+
final iconData = await tester.loadIcon();
196179

197180
// create document, board, grid and calendar views
198181
for (final value in ViewLayoutPB.values) {

frontend/appflowy_flutter/integration_test/mobile/document/page_style_test.dart

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,30 @@
11
import 'package:appflowy/generated/flowy_svgs.g.dart';
2+
import 'package:appflowy/generated/locale_keys.g.dart';
23
import 'package:appflowy/mobile/application/page_style/document_page_style_bloc.dart';
34
import 'package:appflowy/mobile/presentation/base/view_page/app_bar_buttons.dart';
45
import 'package:appflowy/mobile/presentation/bottom_sheet/bottom_sheet_buttons.dart';
6+
import 'package:appflowy/mobile/presentation/mobile_bottom_navigation_bar.dart';
57
import 'package:appflowy/plugins/document/presentation/editor_page.dart';
68
import 'package:appflowy/plugins/document/presentation/editor_plugins/cover/document_immersive_cover.dart';
9+
import 'package:appflowy/plugins/document/presentation/editor_plugins/page_style/_page_style_icon.dart';
10+
import 'package:appflowy/shared/icon_emoji_picker/recent_icons.dart';
11+
import 'package:easy_localization/easy_localization.dart';
712
import 'package:flutter/material.dart';
813
import 'package:flutter_test/flutter_test.dart';
914
import 'package:integration_test/integration_test.dart';
1015

16+
import '../../shared/emoji.dart';
1117
import '../../shared/util.dart';
1218

1319
void main() {
14-
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
20+
setUpAll(() {
21+
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
22+
RecentIcons.enable = false;
23+
});
24+
25+
tearDownAll(() {
26+
RecentIcons.enable = true;
27+
});
1528

1629
group('document page style:', () {
1730
double getCurrentEditorFontSize() {
@@ -114,5 +127,37 @@ void main() {
114127
);
115128
expect(builtInCover, findsOneWidget);
116129
});
130+
131+
testWidgets('page style icon', (tester) async {
132+
await tester.launchInAnonymousMode();
133+
134+
final createPageButton =
135+
find.byKey(BottomNavigationBarItemType.add.valueKey);
136+
await tester.tapButton(createPageButton);
137+
138+
/// toggle the preset button
139+
await tester.tapSvgButton(FlowySvgs.m_layout_s);
140+
141+
/// select document plugins emoji
142+
final pageStyleIcon = find.byType(PageStyleIcon);
143+
144+
/// there should be none of emoji
145+
final noneText = find.text(LocaleKeys.pageStyle_none.tr());
146+
expect(noneText, findsOneWidget);
147+
await tester.tapButton(pageStyleIcon);
148+
149+
/// select an emoji
150+
const emoji = '😄';
151+
await tester.tapEmoji(emoji);
152+
await tester.tapSvgButton(FlowySvgs.m_layout_s);
153+
expect(noneText, findsNothing);
154+
expect(
155+
find.descendant(
156+
of: pageStyleIcon,
157+
matching: find.text(emoji),
158+
),
159+
findsOneWidget,
160+
);
161+
});
117162
});
118163
}

frontend/appflowy_flutter/integration_test/shared/base.dart

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,33 @@ extension AppFlowyTestBase on WidgetTester {
175175
}
176176
}
177177

178+
Future<void> tapDown(
179+
Finder finder, {
180+
int? pointer,
181+
int buttons = kPrimaryButton,
182+
PointerDeviceKind kind = PointerDeviceKind.touch,
183+
bool pumpAndSettle = true,
184+
int milliseconds = 500,
185+
}) async {
186+
final location = getCenter(finder);
187+
final TestGesture gesture = await startGesture(
188+
location,
189+
pointer: pointer,
190+
buttons: buttons,
191+
kind: kind,
192+
);
193+
await gesture.cancel();
194+
await gesture.down(location);
195+
await gesture.cancel();
196+
if (pumpAndSettle) {
197+
await this.pumpAndSettle(
198+
Duration(milliseconds: milliseconds),
199+
EnginePhase.sendSemanticsUpdate,
200+
const Duration(seconds: 15),
201+
);
202+
}
203+
}
204+
178205
Future<void> tapButtonWithName(
179206
String tr, {
180207
int milliseconds = 500,

frontend/appflowy_flutter/integration_test/shared/common_operations.dart

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import 'package:appflowy/plugins/document/presentation/editor_plugins/simple_tab
1313
import 'package:appflowy/plugins/shared/share/share_button.dart';
1414
import 'package:appflowy/shared/feature_flags.dart';
1515
import 'package:appflowy/shared/icon_emoji_picker/flowy_icon_emoji_picker.dart';
16+
import 'package:appflowy/shared/icon_emoji_picker/icon_picker.dart';
1617
import 'package:appflowy/shared/text_field/text_filed_with_metric_lines.dart';
1718
import 'package:appflowy/startup/startup.dart';
1819
import 'package:appflowy/user/presentation/screens/screens.dart';
@@ -23,6 +24,7 @@ import 'package:appflowy/workspace/presentation/home/menu/sidebar/shared/sidebar
2324
import 'package:appflowy/workspace/presentation/home/menu/sidebar/space/shared_widget.dart';
2425
import 'package:appflowy/workspace/presentation/home/menu/sidebar/space/sidebar_space_header.dart';
2526
import 'package:appflowy/workspace/presentation/home/menu/sidebar/space/sidebar_space_menu.dart';
27+
import 'package:appflowy/workspace/presentation/home/menu/sidebar/space/space_icon_popup.dart';
2628
import 'package:appflowy/workspace/presentation/home/menu/sidebar/workspace/_sidebar_workspace_menu.dart';
2729
import 'package:appflowy/workspace/presentation/home/menu/sidebar/workspace/sidebar_workspace.dart';
2830
import 'package:appflowy/workspace/presentation/home/menu/view/draggable_view_item.dart';
@@ -898,6 +900,22 @@ extension CommonOperations on WidgetTester {
898900
await tapAt(Offset.zero);
899901
await pumpUntilNotFound(finder);
900902
}
903+
904+
/// load icon list and return the first one
905+
Future<EmojiIconData> loadIcon() async {
906+
await loadIconGroups();
907+
final groups = kIconGroups!;
908+
final firstGroup = groups.first;
909+
final firstIcon = firstGroup.icons.first;
910+
return EmojiIconData.icon(
911+
IconsData(
912+
firstGroup.name,
913+
firstIcon.content,
914+
firstIcon.name,
915+
builtInSpaceColors.first,
916+
),
917+
);
918+
}
901919
}
902920

903921
extension SettingsFinder on CommonFinders {

frontend/appflowy_flutter/integration_test/shared/emoji.dart

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,17 +31,19 @@ extension EmojiTestExtension on WidgetTester {
3131
matching: find.text(PickerTabType.icon.tr),
3232
);
3333
expect(iconTab, findsOneWidget);
34-
expect(find.byType(FlowyIconPicker), findsNothing);
35-
await tap(iconTab);
36-
await pumpAndSettle();
37-
expect(find.byType(FlowyIconPicker), findsOneWidget);
34+
await tapButton(iconTab);
3835
final selectedSvg = find.descendant(
3936
of: find.byType(FlowyIconPicker),
4037
matching: find.byWidgetPredicate(
4138
(w) => w is FlowySvg && w.svgString == iconsData.iconContent,
4239
),
4340
);
4441
expect(find.byType(IconColorPicker), findsNothing);
42+
43+
/// test for tapping down, it should not display the ColorPicker unless tapping up
44+
await tapDown(selectedSvg);
45+
expect(find.byType(IconColorPicker), findsNothing);
46+
4547
await tapButton(selectedSvg);
4648
final colorPicker = find.byType(IconColorPicker);
4749
expect(colorPicker, findsOneWidget);

frontend/appflowy_flutter/lib/mobile/presentation/base/mobile_view_page.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -268,8 +268,8 @@ class _MobileViewPageState extends State<MobileViewPage> {
268268
return Row(
269269
mainAxisSize: MainAxisSize.min,
270270
children: [
271-
if (icon != null) ...[
272-
EmojiIconWidget(
271+
if (icon != null && icon.value.isNotEmpty) ...[
272+
RawEmojiIconWidget(
273273
emoji: icon.toEmojiIconData(),
274274
emojiSize: 15,
275275
),

frontend/appflowy_flutter/lib/mobile/presentation/home/mobile_home_page_header.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import 'package:appflowy/mobile/presentation/bottom_sheet/bottom_sheet.dart';
55
import 'package:appflowy/mobile/presentation/home/workspaces/workspace_menu_bottom_sheet.dart';
66
import 'package:appflowy/plugins/base/emoji/emoji_picker_screen.dart';
77
import 'package:appflowy/shared/icon_emoji_picker/flowy_icon_emoji_picker.dart';
8+
import 'package:appflowy/shared/icon_emoji_picker/tab.dart';
89
import 'package:appflowy/startup/startup.dart';
910
import 'package:appflowy/util/built_in_svgs.dart';
1011
import 'package:appflowy/workspace/application/user/settings_user_bloc.dart';
@@ -234,6 +235,7 @@ class _UserIcon extends StatelessWidget {
234235
queryParameters: {
235236
MobileEmojiPickerScreen.pageTitle:
236237
LocaleKeys.titleBar_userIcon.tr(),
238+
MobileEmojiPickerScreen.selectTabs: [PickerTabType.emoji.name],
237239
},
238240
).toString(),
239241
);

0 commit comments

Comments
 (0)