mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2025-11-10 15:38:08 +00:00
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
This commit is contained in:
parent
f7f99a162e
commit
15deb8ea79
@ -1,7 +1,9 @@
|
|||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
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/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/workspace/presentation/home/menu/view/view_action_type.dart';
|
||||||
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
|
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
|
||||||
import 'package:appflowy_editor/appflowy_editor.dart';
|
import 'package:appflowy_editor/appflowy_editor.dart';
|
||||||
@ -11,6 +13,7 @@ import 'package:flutter/services.dart';
|
|||||||
import 'package:flutter_test/flutter_test.dart';
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
import 'package:integration_test/integration_test.dart';
|
import 'package:integration_test/integration_test.dart';
|
||||||
|
|
||||||
|
import '../../shared/emoji.dart';
|
||||||
import '../../shared/util.dart';
|
import '../../shared/util.dart';
|
||||||
|
|
||||||
// Test cases for the Document SubPageBlock that needs to be covered:
|
// Test cases for the Document SubPageBlock that needs to be covered:
|
||||||
@ -37,7 +40,14 @@ import '../../shared/util.dart';
|
|||||||
const _defaultPageName = "";
|
const _defaultPageName = "";
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
|
setUpAll(() {
|
||||||
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
||||||
|
RecentIcons.enable = false;
|
||||||
|
});
|
||||||
|
|
||||||
|
tearDownAll(() {
|
||||||
|
RecentIcons.enable = true;
|
||||||
|
});
|
||||||
|
|
||||||
group('Document SubPageBlock tests', () {
|
group('Document SubPageBlock tests', () {
|
||||||
testWidgets('Insert a new SubPageBlock from Slash menu items',
|
testWidgets('Insert a new SubPageBlock from Slash menu items',
|
||||||
@ -498,6 +508,38 @@ void main() {
|
|||||||
|
|
||||||
expect(find.text('Parent'), findsNWidgets(2));
|
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);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,9 +1,7 @@
|
|||||||
import 'package:appflowy/plugins/base/emoji/emoji_picker.dart';
|
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/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/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/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/workspace/presentation/widgets/view_title_bar.dart';
|
||||||
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
|
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
|
||||||
import 'package:flowy_infra_ui/style_widget/text_field.dart';
|
import 'package:flowy_infra_ui/style_widget/text_field.dart';
|
||||||
@ -27,21 +25,6 @@ void main() {
|
|||||||
RecentIcons.enable = true;
|
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 {
|
testWidgets('Update page emoji in sidebar', (tester) async {
|
||||||
await tester.initializeAppFlowy();
|
await tester.initializeAppFlowy();
|
||||||
await tester.tapAnonymousSignInButton();
|
await tester.tapAnonymousSignInButton();
|
||||||
@ -160,7 +143,7 @@ void main() {
|
|||||||
testWidgets('Update page icon in sidebar', (tester) async {
|
testWidgets('Update page icon in sidebar', (tester) async {
|
||||||
await tester.initializeAppFlowy();
|
await tester.initializeAppFlowy();
|
||||||
await tester.tapAnonymousSignInButton();
|
await tester.tapAnonymousSignInButton();
|
||||||
final iconData = await loadIcon();
|
final iconData = await tester.loadIcon();
|
||||||
|
|
||||||
// create document, board, grid and calendar views
|
// create document, board, grid and calendar views
|
||||||
for (final value in ViewLayoutPB.values) {
|
for (final value in ViewLayoutPB.values) {
|
||||||
@ -192,7 +175,7 @@ void main() {
|
|||||||
testWidgets('Update page icon in title bar', (tester) async {
|
testWidgets('Update page icon in title bar', (tester) async {
|
||||||
await tester.initializeAppFlowy();
|
await tester.initializeAppFlowy();
|
||||||
await tester.tapAnonymousSignInButton();
|
await tester.tapAnonymousSignInButton();
|
||||||
final iconData = await loadIcon();
|
final iconData = await tester.loadIcon();
|
||||||
|
|
||||||
// create document, board, grid and calendar views
|
// create document, board, grid and calendar views
|
||||||
for (final value in ViewLayoutPB.values) {
|
for (final value in ViewLayoutPB.values) {
|
||||||
|
|||||||
@ -1,17 +1,30 @@
|
|||||||
import 'package:appflowy/generated/flowy_svgs.g.dart';
|
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/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/base/view_page/app_bar_buttons.dart';
|
||||||
import 'package:appflowy/mobile/presentation/bottom_sheet/bottom_sheet_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_page.dart';
|
||||||
import 'package:appflowy/plugins/document/presentation/editor_plugins/cover/document_immersive_cover.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/material.dart';
|
||||||
import 'package:flutter_test/flutter_test.dart';
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
import 'package:integration_test/integration_test.dart';
|
import 'package:integration_test/integration_test.dart';
|
||||||
|
|
||||||
|
import '../../shared/emoji.dart';
|
||||||
import '../../shared/util.dart';
|
import '../../shared/util.dart';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
|
setUpAll(() {
|
||||||
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
||||||
|
RecentIcons.enable = false;
|
||||||
|
});
|
||||||
|
|
||||||
|
tearDownAll(() {
|
||||||
|
RecentIcons.enable = true;
|
||||||
|
});
|
||||||
|
|
||||||
group('document page style:', () {
|
group('document page style:', () {
|
||||||
double getCurrentEditorFontSize() {
|
double getCurrentEditorFontSize() {
|
||||||
@ -114,5 +127,37 @@ void main() {
|
|||||||
);
|
);
|
||||||
expect(builtInCover, findsOneWidget);
|
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,
|
||||||
|
);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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(
|
Future<void> tapButtonWithName(
|
||||||
String tr, {
|
String tr, {
|
||||||
int milliseconds = 500,
|
int milliseconds = 500,
|
||||||
|
|||||||
@ -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/plugins/shared/share/share_button.dart';
|
||||||
import 'package:appflowy/shared/feature_flags.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/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/shared/text_field/text_filed_with_metric_lines.dart';
|
||||||
import 'package:appflowy/startup/startup.dart';
|
import 'package:appflowy/startup/startup.dart';
|
||||||
import 'package:appflowy/user/presentation/screens/screens.dart';
|
import 'package:appflowy/user/presentation/screens/screens.dart';
|
||||||
@ -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/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_header.dart';
|
||||||
import 'package:appflowy/workspace/presentation/home/menu/sidebar/space/sidebar_space_menu.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_menu.dart';
|
||||||
import 'package:appflowy/workspace/presentation/home/menu/sidebar/workspace/sidebar_workspace.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';
|
import 'package:appflowy/workspace/presentation/home/menu/view/draggable_view_item.dart';
|
||||||
@ -898,6 +900,22 @@ extension CommonOperations on WidgetTester {
|
|||||||
await tapAt(Offset.zero);
|
await tapAt(Offset.zero);
|
||||||
await pumpUntilNotFound(finder);
|
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 {
|
extension SettingsFinder on CommonFinders {
|
||||||
|
|||||||
@ -42,6 +42,11 @@ extension EmojiTestExtension on WidgetTester {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
expect(find.byType(IconColorPicker), findsNothing);
|
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);
|
await tapButton(selectedSvg);
|
||||||
final colorPicker = find.byType(IconColorPicker);
|
final colorPicker = find.byType(IconColorPicker);
|
||||||
expect(colorPicker, findsOneWidget);
|
expect(colorPicker, findsOneWidget);
|
||||||
|
|||||||
@ -178,6 +178,7 @@ class MobileViewPage extends StatelessWidget {
|
|||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
text: TextSpan(
|
text: TextSpan(
|
||||||
children: [
|
children: [
|
||||||
|
if (icon.isNotEmpty)
|
||||||
WidgetSpan(
|
WidgetSpan(
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
width: 20,
|
width: 20,
|
||||||
|
|||||||
@ -48,11 +48,14 @@ class _PageStyleIconState extends State<PageStyleIcon> {
|
|||||||
const HSpace(16.0),
|
const HSpace(16.0),
|
||||||
FlowyText(LocaleKeys.document_plugins_emoji.tr()),
|
FlowyText(LocaleKeys.document_plugins_emoji.tr()),
|
||||||
const Spacer(),
|
const Spacer(),
|
||||||
RawEmojiIconWidget(
|
icon.isEmpty
|
||||||
emoji: icon.isNotEmpty
|
? FlowyText(
|
||||||
? icon
|
LocaleKeys.pageStyle_none.tr(),
|
||||||
: EmojiIconData.emoji(LocaleKeys.pageStyle_none.tr()),
|
fontSize: 16.0,
|
||||||
emojiSize: icon.isNotEmpty ? 22.0 : 16.0,
|
)
|
||||||
|
: RawEmojiIconWidget(
|
||||||
|
emoji: icon,
|
||||||
|
emojiSize: 22.0,
|
||||||
),
|
),
|
||||||
const HSpace(6.0),
|
const HSpace(6.0),
|
||||||
const FlowySvg(FlowySvgs.m_page_style_arrow_right_s),
|
const FlowySvg(FlowySvgs.m_page_style_arrow_right_s),
|
||||||
|
|||||||
@ -1,8 +1,10 @@
|
|||||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||||
import 'package:appflowy/mobile/application/mobile_router.dart';
|
import 'package:appflowy/mobile/application/mobile_router.dart';
|
||||||
|
import 'package:appflowy/plugins/document/presentation/editor_plugins/header/emoji_icon_widget.dart';
|
||||||
import 'package:appflowy/plugins/document/presentation/editor_plugins/mention/mention_page_block.dart';
|
import 'package:appflowy/plugins/document/presentation/editor_plugins/mention/mention_page_block.dart';
|
||||||
import 'package:appflowy/plugins/document/presentation/editor_plugins/shared_context/shared_context.dart';
|
import 'package:appflowy/plugins/document/presentation/editor_plugins/shared_context/shared_context.dart';
|
||||||
import 'package:appflowy/plugins/trash/application/trash_listener.dart';
|
import 'package:appflowy/plugins/trash/application/trash_listener.dart';
|
||||||
|
import 'package:appflowy/shared/icon_emoji_picker/flowy_icon_emoji_picker.dart';
|
||||||
import 'package:appflowy/startup/startup.dart';
|
import 'package:appflowy/startup/startup.dart';
|
||||||
import 'package:appflowy/workspace/application/tabs/tabs_bloc.dart';
|
import 'package:appflowy/workspace/application/tabs/tabs_bloc.dart';
|
||||||
import 'package:appflowy/workspace/application/view/view_ext.dart';
|
import 'package:appflowy/workspace/application/view/view_ext.dart';
|
||||||
@ -15,7 +17,6 @@ import 'package:appflowy_editor/appflowy_editor.dart';
|
|||||||
import 'package:appflowy_result/appflowy_result.dart';
|
import 'package:appflowy_result/appflowy_result.dart';
|
||||||
import 'package:collection/collection.dart';
|
import 'package:collection/collection.dart';
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:flowy_infra/theme_extension.dart';
|
|
||||||
import 'package:flowy_infra_ui/style_widget/text.dart';
|
import 'package:flowy_infra_ui/style_widget/text.dart';
|
||||||
import 'package:flowy_infra_ui/widget/spacing.dart';
|
import 'package:flowy_infra_ui/widget/spacing.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
@ -242,12 +243,9 @@ class SubPageBlockComponentState extends State<SubPageBlockComponent>
|
|||||||
children: [
|
children: [
|
||||||
const HSpace(10),
|
const HSpace(10),
|
||||||
view.icon.value.isNotEmpty
|
view.icon.value.isNotEmpty
|
||||||
? FlowyText.emoji(
|
? RawEmojiIconWidget(
|
||||||
view.icon.value,
|
emoji: view.icon.toEmojiIconData(),
|
||||||
fontSize: textStyle.fontSize,
|
emojiSize: textStyle.fontSize ?? 16.0,
|
||||||
lineHeight: textStyle.height,
|
|
||||||
color:
|
|
||||||
AFThemeExtension.of(context).strongText,
|
|
||||||
)
|
)
|
||||||
: view.defaultIcon(),
|
: view.defaultIcon(),
|
||||||
const HSpace(6),
|
const HSpace(6),
|
||||||
|
|||||||
@ -39,8 +39,9 @@ class IconGroup {
|
|||||||
final filteredIcons = icons
|
final filteredIcons = icons
|
||||||
.where(
|
.where(
|
||||||
(icon) =>
|
(icon) =>
|
||||||
icon.keywords.any((k) => k.contains(lowercaseKey)) ||
|
icon.keywords
|
||||||
icon.name.contains(lowercaseKey),
|
.any((k) => k.toLowerCase().contains(lowercaseKey)) ||
|
||||||
|
icon.name.toLowerCase().contains(lowercaseKey),
|
||||||
)
|
)
|
||||||
.toList();
|
.toList();
|
||||||
return IconGroup(name: name, icons: filteredIcons);
|
return IconGroup(name: name, icons: filteredIcons);
|
||||||
@ -84,3 +85,23 @@ class Icon {
|
|||||||
return '${iconGroup!.name}/$name';
|
return '${iconGroup!.name}/$name';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class RecentIcon {
|
||||||
|
factory RecentIcon.fromJson(Map<String, dynamic> json) =>
|
||||||
|
RecentIcon(_$IconFromJson(json), json['groupName'] ?? '');
|
||||||
|
|
||||||
|
RecentIcon(this.icon, this.groupName);
|
||||||
|
|
||||||
|
final Icon icon;
|
||||||
|
final String groupName;
|
||||||
|
|
||||||
|
String get name => icon.name;
|
||||||
|
|
||||||
|
List<String> get keywords => icon.keywords;
|
||||||
|
|
||||||
|
String get content => icon.content;
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() => _$IconToJson(
|
||||||
|
Icon(name: name, keywords: keywords, content: content),
|
||||||
|
)..addAll({'groupName': groupName});
|
||||||
|
}
|
||||||
|
|||||||
@ -118,10 +118,13 @@ class _FlowyIconPickerState extends State<FlowyIconPicker> {
|
|||||||
iconGroups.add(
|
iconGroups.add(
|
||||||
IconGroup(
|
IconGroup(
|
||||||
name: _kRecentIconGroupName,
|
name: _kRecentIconGroupName,
|
||||||
icons: recentIcons.sublist(
|
icons: recentIcons
|
||||||
|
.sublist(
|
||||||
0,
|
0,
|
||||||
min(recentIcons.length, widget.iconPerLine),
|
min(recentIcons.length, widget.iconPerLine),
|
||||||
),
|
)
|
||||||
|
.map((e) => e.icon)
|
||||||
|
.toList(),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -171,7 +174,7 @@ class _FlowyIconPickerState extends State<FlowyIconPicker> {
|
|||||||
color,
|
color,
|
||||||
).toResult(isRandom: true),
|
).toResult(isRandom: true),
|
||||||
);
|
);
|
||||||
RecentIcons.putIcon(value.$2);
|
RecentIcons.putIcon(RecentIcon(value.$2, value.$1.name));
|
||||||
},
|
},
|
||||||
onKeywordChanged: (keyword) => {
|
onKeywordChanged: (keyword) => {
|
||||||
debounce.call(() {
|
debounce.call(() {
|
||||||
@ -303,30 +306,38 @@ class _IconPickerState extends State<IconPicker> {
|
|||||||
icon: icon,
|
icon: icon,
|
||||||
mutex: mutex,
|
mutex: mutex,
|
||||||
onSelectedColor: (context, color) {
|
onSelectedColor: (context, color) {
|
||||||
|
String groupName = iconGroup.name;
|
||||||
|
if (groupName == _kRecentIconGroupName) {
|
||||||
|
groupName = getGroupName(index);
|
||||||
|
}
|
||||||
widget.onSelectedIcon(
|
widget.onSelectedIcon(
|
||||||
IconsData(
|
IconsData(
|
||||||
iconGroup.name,
|
groupName,
|
||||||
icon.content,
|
icon.content,
|
||||||
icon.name,
|
icon.name,
|
||||||
color,
|
color,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
RecentIcons.putIcon(icon);
|
RecentIcons.putIcon(RecentIcon(icon, groupName));
|
||||||
PopoverContainer.of(context).close();
|
PopoverContainer.of(context).close();
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
: _IconNoBackground(
|
: _IconNoBackground(
|
||||||
icon: icon,
|
icon: icon,
|
||||||
onSelectedIcon: () {
|
onSelectedIcon: () {
|
||||||
|
String groupName = iconGroup.name;
|
||||||
|
if (groupName == _kRecentIconGroupName) {
|
||||||
|
groupName = getGroupName(index);
|
||||||
|
}
|
||||||
widget.onSelectedIcon(
|
widget.onSelectedIcon(
|
||||||
IconsData(
|
IconsData(
|
||||||
iconGroup.name,
|
groupName,
|
||||||
icon.content,
|
icon.content,
|
||||||
icon.name,
|
icon.name,
|
||||||
null,
|
null,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
RecentIcons.putIcon(icon);
|
RecentIcons.putIcon(RecentIcon(icon, groupName));
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
@ -341,6 +352,16 @@ class _IconPickerState extends State<IconPicker> {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String getGroupName(int index) {
|
||||||
|
final recentIcons = RecentIcons.getIconsSync();
|
||||||
|
try {
|
||||||
|
return recentIcons[index].groupName;
|
||||||
|
} catch (e) {
|
||||||
|
Log.error('getGroupName with index: $index error', e);
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class _IconNoBackground extends StatelessWidget {
|
class _IconNoBackground extends StatelessWidget {
|
||||||
@ -392,12 +413,20 @@ class _Icon extends StatefulWidget {
|
|||||||
class _IconState extends State<_Icon> {
|
class _IconState extends State<_Icon> {
|
||||||
final PopoverController _popoverController = PopoverController();
|
final PopoverController _popoverController = PopoverController();
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
super.dispose();
|
||||||
|
_popoverController.close();
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return AppFlowyPopover(
|
return AppFlowyPopover(
|
||||||
direction: PopoverDirection.bottomWithCenterAligned,
|
direction: PopoverDirection.bottomWithCenterAligned,
|
||||||
|
controller: _popoverController,
|
||||||
offset: const Offset(0, 6),
|
offset: const Offset(0, 6),
|
||||||
mutex: widget.mutex,
|
mutex: widget.mutex,
|
||||||
|
clickHandler: PopoverClickHandler.gestureDetector,
|
||||||
child: _IconNoBackground(
|
child: _IconNoBackground(
|
||||||
icon: widget.icon,
|
icon: widget.icon,
|
||||||
onSelectedIcon: () => _popoverController.show(),
|
onSelectedIcon: () => _popoverController.show(),
|
||||||
|
|||||||
@ -22,13 +22,10 @@ class RecentIcons {
|
|||||||
await _put(FlowyIconType.emoji, id);
|
await _put(FlowyIconType.emoji, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Future<void> putIcon(Icon icon) async {
|
static Future<void> putIcon(RecentIcon icon) async {
|
||||||
await _put(
|
await _put(
|
||||||
FlowyIconType.icon,
|
FlowyIconType.icon,
|
||||||
jsonEncode(
|
jsonEncode(icon.toJson()),
|
||||||
Icon(name: icon.name, keywords: icon.keywords, content: icon.content)
|
|
||||||
.toJson(),
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -37,12 +34,18 @@ class RecentIcons {
|
|||||||
return _dataMap[FlowyIconType.emoji.name] ?? [];
|
return _dataMap[FlowyIconType.emoji.name] ?? [];
|
||||||
}
|
}
|
||||||
|
|
||||||
static Future<List<Icon>> getIcons() async {
|
static Future<List<RecentIcon>> getIcons() async {
|
||||||
await _load();
|
await _load();
|
||||||
|
return getIconsSync();
|
||||||
|
}
|
||||||
|
|
||||||
|
static List<RecentIcon> getIconsSync() {
|
||||||
final iconList = _dataMap[FlowyIconType.icon.name] ?? [];
|
final iconList = _dataMap[FlowyIconType.icon.name] ?? [];
|
||||||
try {
|
try {
|
||||||
return iconList
|
return iconList
|
||||||
.map((e) => Icon.fromJson(jsonDecode(e) as Map<String, dynamic>))
|
.map(
|
||||||
|
(e) => RecentIcon.fromJson(jsonDecode(e) as Map<String, dynamic>),
|
||||||
|
)
|
||||||
.toList();
|
.toList();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
Log.error('RecentIcons getIcons with :$iconList', e);
|
Log.error('RecentIcons getIcons with :$iconList', e);
|
||||||
|
|||||||
@ -46,16 +46,17 @@ void main() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('putIcons', () async {
|
test('putIcons', () async {
|
||||||
List<Icon> icons = await RecentIcons.getIcons();
|
List<RecentIcon> icons = await RecentIcons.getIcons();
|
||||||
assert(icons.isEmpty);
|
assert(icons.isEmpty);
|
||||||
await loadIconGroups();
|
await loadIconGroups();
|
||||||
final groups = kIconGroups!;
|
final groups = kIconGroups!;
|
||||||
final List<Icon> localIcons = [];
|
final List<RecentIcon> localIcons = [];
|
||||||
for (final e in groups) {
|
for (final e in groups) {
|
||||||
localIcons.addAll(e.icons);
|
localIcons.addAll(e.icons.map((e) => RecentIcon(e, e.name)).toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool equalIcon(Icon a, Icon b) =>
|
bool equalIcon(RecentIcon a, RecentIcon b) =>
|
||||||
|
a.groupName == b.groupName &&
|
||||||
a.name == b.name &&
|
a.name == b.name &&
|
||||||
a.keywords.equals(b.keywords) &&
|
a.keywords.equals(b.keywords) &&
|
||||||
a.content == b.content;
|
a.content == b.content;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user