feat: optimize editor toolbar tooltip (#5889)

* chore: improve icon picker dark mode color

* feat: optimize editor toolbar tooltip style

* feat: customize markdown item tooltip message

* chore: find the tooltip by rich message

* feat: add hover effect in toolbar item

* feat: add hover effect in toolbar item

* chore: optimize hover color in light mode

* chore: fix integration test

* chore: optimize align & font toolbar item

* chore: fix integration test
This commit is contained in:
Lucas.Xu 2024-08-07 11:37:30 +08:00 committed by GitHub
parent a798b037db
commit e279ad1cc7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
19 changed files with 293 additions and 233 deletions

View File

@ -33,7 +33,7 @@ void main() {
);
// tap the inline math equation button
final inlineMathEquationButton = find.byTooltip(
final inlineMathEquationButton = find.findFlowyTooltip(
LocaleKeys.document_plugins_createInlineMathEquation.tr(),
);
await tester.tapButton(inlineMathEquationButton);
@ -78,7 +78,7 @@ void main() {
);
// tap the inline math equation button
var inlineMathEquationButton = find.byTooltip(
var inlineMathEquationButton = find.findFlowyTooltip(
LocaleKeys.document_plugins_createInlineMathEquation.tr(),
);
await tester.tapButton(inlineMathEquationButton);
@ -93,11 +93,11 @@ void main() {
);
// expect to the see the inline math equation button is highlighted
inlineMathEquationButton = find.byWidgetPredicate(
(widget) =>
widget is SVGIconItemWidget &&
widget.tooltip ==
LocaleKeys.document_plugins_createInlineMathEquation.tr(),
inlineMathEquationButton = find.descendant(
of: find.findFlowyTooltip(
LocaleKeys.document_plugins_createInlineMathEquation.tr(),
),
matching: find.byType(SVGIconItemWidget),
);
expect(
tester.widget<SVGIconItemWidget>(inlineMathEquationButton).isHighlight,

View File

@ -1,113 +0,0 @@
import 'package:appflowy/plugins/document/presentation/editor_plugins/openai/service/ai_client.dart';
import 'package:appflowy/startup/startup.dart';
import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:appflowy_editor/src/render/toolbar/toolbar_widget.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import '../../shared/mock/mock_openai_repository.dart';
import '../../shared/util.dart';
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
const service = TestWorkspaceService(TestWorkspace.aiWorkSpace);
group('integration tests for open-ai smart menu', () {
setUpAll(() async => service.setUpAll());
setUp(() async => service.setUp());
testWidgets('testing selection on open-ai smart menu replace',
(tester) async {
final appFlowyEditor = await setUpOpenAITesting(tester);
final editorState = appFlowyEditor.editorState;
editorState.service.selectionService.updateSelection(
Selection(
start: Position(path: [1], offset: 4),
end: Position(path: [1], offset: 10),
),
);
await tester.pumpAndSettle(const Duration(milliseconds: 500));
await tester.pumpAndSettle();
expect(find.byType(ToolbarWidget), findsAtLeastNWidgets(1));
await tester.tap(find.byTooltip('AI Assistants'));
await tester.pumpAndSettle(const Duration(milliseconds: 500));
await tester.tap(find.text('Summarize'));
await tester.pumpAndSettle();
await tester
.tap(find.byType(FlowyRichTextButton, skipOffstage: false).first);
await tester.pumpAndSettle();
expect(
editorState.service.selectionService.currentSelection.value,
Selection(
start: Position(path: [1], offset: 4),
end: Position(path: [1], offset: 84),
),
);
});
testWidgets('testing selection on open-ai smart menu insert',
(tester) async {
final appFlowyEditor = await setUpOpenAITesting(tester);
final editorState = appFlowyEditor.editorState;
editorState.service.selectionService.updateSelection(
Selection(
start: Position(path: [1]),
end: Position(path: [1], offset: 5),
),
);
await tester.pumpAndSettle(const Duration(milliseconds: 500));
await tester.pumpAndSettle();
expect(find.byType(ToolbarWidget), findsAtLeastNWidgets(1));
await tester.tap(find.byTooltip('AI Assistants'));
await tester.pumpAndSettle(const Duration(milliseconds: 500));
await tester.tap(find.text('Summarize'));
await tester.pumpAndSettle();
await tester
.tap(find.byType(FlowyRichTextButton, skipOffstage: false).at(1));
await tester.pumpAndSettle();
expect(
editorState.service.selectionService.currentSelection.value,
Selection(
start: Position(path: [2]),
end: Position(path: [3]),
),
);
});
});
}
Future<AppFlowyEditor> setUpOpenAITesting(WidgetTester tester) async {
await tester.initializeAppFlowy();
await mockOpenAIRepository();
await simulateKeyDownEvent(LogicalKeyboardKey.controlLeft);
await simulateKeyDownEvent(LogicalKeyboardKey.backslash);
await tester.pumpAndSettle();
final Finder editor = find.byType(AppFlowyEditor);
await tester.tap(editor);
await tester.pumpAndSettle();
return tester.state(editor).widget as AppFlowyEditor;
}
Future<void> mockOpenAIRepository() async {
await getIt.unregister<AIRepository>();
getIt.registerFactoryAsync<AIRepository>(
() => Future.value(
MockOpenAIRepository(),
),
);
return;
}

View File

@ -1,9 +1,6 @@
import 'dart:async';
import 'dart:io';
import 'package:flutter/gestures.dart';
import 'package:flutter/services.dart';
import 'package:appflowy/env/cloud_env.dart';
import 'package:appflowy/env/cloud_env_test.dart';
import 'package:appflowy/startup/entry_point.dart';
@ -16,6 +13,8 @@ import 'package:appflowy/user/presentation/screens/sign_in_screen/widgets/widget
import 'package:appflowy/workspace/application/settings/prelude.dart';
import 'package:flowy_infra/uuid.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:path/path.dart' as p;
import 'package:path_provider/path_provider.dart';
@ -231,6 +230,16 @@ extension AppFlowyFinderTestBase on CommonFinders {
(widget) => widget is FlowyText && widget.text == text,
);
}
Finder findFlowyTooltip(String richMessage, {bool skipOffstage = true}) {
return byWidgetPredicate(
(widget) =>
widget is FlowyTooltip &&
widget.richMessage != null &&
widget.richMessage!.toPlainText().contains(richMessage),
skipOffstage: skipOffstage,
);
}
}
Future<void> useTestSupabaseCloud() async {

View File

@ -3,7 +3,7 @@ import 'dart:ui';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/plugins/base/emoji/emoji_picker.dart';
import 'package:appflowy/plugins/base/emoji/emoji_skin_tone.dart';
import 'package:appflowy/shared/icon_emoji_picker/emoji_skin_tone.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/actions/block_action_add_button.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/actions/block_action_option_button.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/header/cover_editor.dart';

View File

@ -1,5 +1,5 @@
import 'package:appflowy/plugins/base/emoji/emoji_picker_header.dart';
import 'package:appflowy/plugins/base/emoji/emoji_skin_tone.dart';
import 'package:appflowy/shared/icon_emoji_picker/emoji_skin_tone.dart';
import 'package:appflowy/shared/icon_emoji_picker/emoji_search_bar.dart';
import 'package:flowy_infra/size.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';

View File

@ -387,6 +387,8 @@ class _AppFlowyEditorPageState extends State<AppFlowyEditorPage> {
editorState: editorState,
editorScrollController: editorScrollController,
textDirection: textDirection,
tooltipBuilder: (context, id, message, child) => widget.styleCustomizer
.buildToolbarItemTooltip(context, id, message, child,),
child: editor,
),
);

View File

@ -9,12 +9,13 @@ import 'package:flutter/material.dart';
const String leftAlignmentKey = 'left';
const String centerAlignmentKey = 'center';
const String rightAlignmentKey = 'right';
const String kAlignToolbarItemId = 'editor.align';
final alignToolbarItem = ToolbarItem(
id: 'editor.align',
id: kAlignToolbarItemId,
group: 4,
isActive: onlyShowInTextType,
builder: (context, editorState, highlightColor, _) {
builder: (context, editorState, highlightColor, _, tooltipBuilder) {
final selection = editorState.selection!;
final nodes = editorState.getNodesInSelection(selection);
@ -37,35 +38,37 @@ final alignToolbarItem = ToolbarItem(
data = FlowySvgs.toolbar_align_right_s;
}
final child = FlowySvg(
Widget child = FlowySvg(
data,
size: const Size.square(16),
color: isHighlight ? highlightColor : Colors.white,
);
return MouseRegion(
cursor: SystemMouseCursors.click,
child: FlowyTooltip(
message: LocaleKeys.document_plugins_optionAction_align.tr(),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 4.0),
child: _AlignmentButtons(
child: child,
onAlignChanged: (align) async {
await editorState.updateNode(
selection,
(node) => node.copyWith(
attributes: {
...node.attributes,
blockComponentAlign: align,
},
),
);
child = _AlignmentButtons(
child: child,
onAlignChanged: (align) async {
await editorState.updateNode(
selection,
(node) => node.copyWith(
attributes: {
...node.attributes,
blockComponentAlign: align,
},
),
),
),
);
},
);
if (tooltipBuilder != null) {
child = tooltipBuilder(
context,
kAlignToolbarItemId,
LocaleKeys.document_plugins_optionAction_align.tr(),
child,
);
}
return child;
},
);
@ -83,13 +86,15 @@ class _AlignmentButtons extends StatefulWidget {
}
class _AlignmentButtonsState extends State<_AlignmentButtons> {
final controller = PopoverController();
@override
Widget build(BuildContext context) {
return AppFlowyPopover(
windowPadding: const EdgeInsets.all(0),
margin: const EdgeInsets.all(4),
margin: const EdgeInsets.symmetric(vertical: 2.0),
direction: PopoverDirection.bottomWithCenterAligned,
offset: const Offset(0, 10),
offset: const Offset(0, 12),
decorationColor: Theme.of(context).colorScheme.onTertiary,
borderRadius: const BorderRadius.all(Radius.circular(4)),
popupBuilder: (_) {
@ -99,7 +104,12 @@ class _AlignmentButtonsState extends State<_AlignmentButtons> {
onClose: () {
keepEditorFocusNotifier.decrease();
},
child: widget.child,
child: FlowyButton(
useIntrinsicWidth: true,
text: widget.child,
hoverColor: Colors.grey.withOpacity(0.3),
onTap: () => controller.show(),
),
);
}
}
@ -114,7 +124,7 @@ class _AlignButtons extends StatelessWidget {
@override
Widget build(BuildContext context) {
return SizedBox(
height: 32,
height: 28,
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
@ -156,17 +166,16 @@ class _AlignButton extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MouseRegion(
cursor: SystemMouseCursors.click,
child: GestureDetector(
onTap: onTap,
child: FlowyTooltip(
message: tooltips,
child: FlowySvg(
icon,
size: const Size.square(16),
color: Colors.white,
),
return FlowyButton(
useIntrinsicWidth: true,
hoverColor: Colors.grey.withOpacity(0.3),
onTap: onTap,
text: FlowyTooltip(
message: tooltips,
child: FlowySvg(
icon,
size: const Size.square(16),
color: Colors.white,
),
),
);
@ -179,7 +188,7 @@ class _Divider extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(8),
padding: const EdgeInsets.all(4),
child: Container(
width: 1,
color: Colors.grey,

View File

@ -1,6 +1,3 @@
import 'package:appflowy/workspace/application/settings/appearance/base_appearance.dart';
import 'package:flutter/material.dart';
import 'package:appflowy/generated/flowy_svgs.g.dart';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/plugins/document/application/document_appearance_cubit.dart';
@ -9,6 +6,7 @@ import 'package:appflowy/util/font_family_extension.dart';
import 'package:appflowy/util/levenshtein.dart';
import 'package:appflowy/workspace/application/appearance_defaults.dart';
import 'package:appflowy/workspace/application/settings/appearance/appearance_cubit.dart';
import 'package:appflowy/workspace/application/settings/appearance/base_appearance.dart';
import 'package:appflowy/workspace/presentation/settings/shared/setting_list_tile.dart';
import 'package:appflowy/workspace/presentation/settings/shared/setting_value_dropdown.dart';
import 'package:appflowy_backend/log.dart';
@ -20,56 +18,66 @@ import 'package:flowy_infra/theme_extension.dart';
import 'package:flowy_infra_ui/style_widget/button.dart';
import 'package:flowy_infra_ui/style_widget/text.dart';
import 'package:flowy_infra_ui/style_widget/text_field.dart';
import 'package:flowy_infra_ui/widget/flowy_tooltip.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:google_fonts/google_fonts.dart';
const kFontToolbarItemId = 'editor.font';
final customizeFontToolbarItem = ToolbarItem(
id: 'editor.font',
id: kFontToolbarItemId,
group: 4,
isActive: onlyShowInTextType,
builder: (context, editorState, highlightColor, _) {
builder: (context, editorState, highlightColor, _, tooltipBuilder) {
final selection = editorState.selection!;
final popoverController = PopoverController();
final String? currentFontFamily = editorState
.getDeltaAttributeValueInSelection(AppFlowyRichTextKeys.fontFamily);
return MouseRegion(
cursor: SystemMouseCursors.click,
child: FontFamilyDropDown(
currentFontFamily: currentFontFamily ?? '',
offset: const Offset(0, 12),
popoverController: popoverController,
onOpen: () => keepEditorFocusNotifier.increase(),
onClose: () => keepEditorFocusNotifier.decrease(),
showResetButton: true,
onFontFamilyChanged: (fontFamily) async {
popoverController.close();
try {
await editorState.formatDelta(selection, {
AppFlowyRichTextKeys.fontFamily: fontFamily,
});
} catch (e) {
Log.error('Failed to set font family: $e');
}
},
onResetFont: () async {
popoverController.close();
await editorState
.formatDelta(selection, {AppFlowyRichTextKeys.fontFamily: null});
},
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 4.0),
child: FlowyTooltip(
message: LocaleKeys.document_plugins_fonts.tr(),
child: const FlowySvg(
FlowySvgs.font_family_s,
size: Size.square(16.0),
color: Colors.white,
),
),
Widget child = FontFamilyDropDown(
currentFontFamily: currentFontFamily ?? '',
offset: const Offset(0, 12),
popoverController: popoverController,
onOpen: () => keepEditorFocusNotifier.increase(),
onClose: () => keepEditorFocusNotifier.decrease(),
showResetButton: true,
onFontFamilyChanged: (fontFamily) async {
popoverController.close();
try {
await editorState.formatDelta(selection, {
AppFlowyRichTextKeys.fontFamily: fontFamily,
});
} catch (e) {
Log.error('Failed to set font family: $e');
}
},
onResetFont: () async {
popoverController.close();
await editorState
.formatDelta(selection, {AppFlowyRichTextKeys.fontFamily: null});
},
child: FlowyButton(
useIntrinsicWidth: true,
hoverColor: Colors.grey.withOpacity(0.3),
onTap: () => popoverController.show(),
text: const FlowySvg(
FlowySvgs.font_family_s,
size: Size.square(16.0),
color: Colors.white,
),
),
);
if (tooltipBuilder != null) {
child = tooltipBuilder(
context,
kFontToolbarItemId,
LocaleKeys.document_plugins_fonts.tr(),
child,
);
}
return child;
},
);

View File

@ -5,11 +5,13 @@ import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
const _kInlineMathEquationToolbarItemId = 'editor.inline_math_equation';
final ToolbarItem inlineMathEquationItem = ToolbarItem(
id: 'editor.inline_math_equation',
id: _kInlineMathEquationToolbarItemId,
group: 2,
isActive: onlyShowInSingleSelectionAndTextType,
builder: (context, editorState, highlightColor, _) {
builder: (context, editorState, highlightColor, _, tooltipBuilder) {
final selection = editorState.selection!;
final nodes = editorState.getNodesInSelection(selection);
final isHighlight = nodes.allSatisfyInSelection(selection, (delta) {
@ -17,7 +19,7 @@ final ToolbarItem inlineMathEquationItem = ToolbarItem(
(attributes) => attributes[InlineMathEquationKeys.formula] != null,
);
});
return SVGIconItemWidget(
final child = SVGIconItemWidget(
iconBuilder: (_) => FlowySvg(
FlowySvgs.math_lg,
size: const Size.square(16),
@ -25,7 +27,6 @@ final ToolbarItem inlineMathEquationItem = ToolbarItem(
),
isHighlight: isHighlight,
highlightColor: highlightColor,
tooltip: LocaleKeys.document_plugins_createInlineMathEquation.tr(),
onPressed: () async {
final selection = editorState.selection;
if (selection == null || selection.isCollapsed) {
@ -71,5 +72,16 @@ final ToolbarItem inlineMathEquationItem = ToolbarItem(
await editorState.apply(transaction);
},
);
if (tooltipBuilder != null) {
return tooltipBuilder(
context,
_kInlineMathEquationToolbarItemId,
LocaleKeys.document_plugins_createInlineMathEquation.tr(),
child,
);
}
return child;
},
);

View File

@ -11,12 +11,15 @@ import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra_ui/style_widget/icon_button.dart';
import 'package:flutter/material.dart';
const _kSmartEditToolbarItemId = 'appflowy.editor.smart_edit';
final ToolbarItem smartEditItem = ToolbarItem(
id: 'appflowy.editor.smart_edit',
id: _kSmartEditToolbarItemId,
group: 0,
isActive: onlyShowInSingleSelectionAndTextType,
builder: (context, editorState, _, __) => SmartEditActionList(
builder: (context, editorState, _, __, tooltipBuilder) => SmartEditActionList(
editorState: editorState,
tooltipBuilder: tooltipBuilder,
),
);
@ -24,9 +27,11 @@ class SmartEditActionList extends StatefulWidget {
const SmartEditActionList({
super.key,
required this.editorState,
this.tooltipBuilder,
});
final EditorState editorState;
final ToolbarTooltipBuilder? tooltipBuilder;
@override
State<SmartEditActionList> createState() => _SmartEditActionListState();
@ -60,11 +65,8 @@ class _SmartEditActionListState extends State<SmartEditActionList> {
onClosed: () => keepEditorFocusNotifier.decrease(),
buildChild: (controller) {
keepEditorFocusNotifier.increase();
return FlowyIconButton(
final child = FlowyIconButton(
hoverColor: Colors.transparent,
tooltipText: isAIEnabled
? LocaleKeys.document_plugins_smartEdit.tr()
: LocaleKeys.document_plugins_appflowyAIEditDisabled.tr(),
preferBelow: false,
icon: const Icon(
Icons.lightbulb_outline,
@ -83,6 +85,19 @@ class _SmartEditActionListState extends State<SmartEditActionList> {
}
},
);
if (widget.tooltipBuilder != null) {
return widget.tooltipBuilder!(
context,
_kSmartEditToolbarItemId,
isAIEnabled
? LocaleKeys.document_plugins_smartEdit.tr()
: LocaleKeys.document_plugins_appflowyAIEditDisabled.tr(),
child,
);
}
return child;
},
onSelected: (action, controller) {
controller.close();

View File

@ -1,4 +1,7 @@
import 'dart:io';
import 'package:appflowy/core/helpers/url_launcher.dart';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/mobile/application/page_style/document_page_style_bloc.dart';
import 'package:appflowy/plugins/document/application/document_appearance_cubit.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/base/font_colors.dart';
@ -13,7 +16,10 @@ import 'package:appflowy/workspace/application/settings/appearance/appearance_cu
import 'package:appflowy/workspace/application/settings/appearance/base_appearance.dart';
import 'package:appflowy_editor/appflowy_editor.dart' hide Log;
import 'package:collection/collection.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra/theme_extension.dart';
import 'package:flowy_infra_ui/style_widget/hover.dart';
import 'package:flowy_infra_ui/widget/flowy_tooltip.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
@ -394,4 +400,83 @@ class EditorStyleCustomizer {
after,
);
}
Widget buildToolbarItemTooltip(
BuildContext context,
String id,
String message,
Widget child,
) {
final tooltipMessage = _buildTooltipMessage(id, message);
child = FlowyTooltip(
richMessage: tooltipMessage,
preferBelow: false,
verticalOffset: 20,
child: child,
);
// the align/font toolbar item doesn't need the hover effect
final toolbarItemsWithoutHover = {
kFontToolbarItemId,
kAlignToolbarItemId,
};
if (!toolbarItemsWithoutHover.contains(id)) {
child = Padding(
padding: const EdgeInsets.symmetric(vertical: 4.0),
child: FlowyHover(
style: HoverStyle(
hoverColor: Colors.grey.withOpacity(0.3),
),
child: child,
),
);
}
return child;
}
TextSpan _buildTooltipMessage(String id, String message) {
final markdownItemTooltips = {
'underline': (LocaleKeys.toolbar_underline.tr(), 'U'),
'bold': (LocaleKeys.toolbar_bold.tr(), 'B'),
'italic': (LocaleKeys.toolbar_italic.tr(), 'I'),
'strikethrough': (LocaleKeys.toolbar_strike.tr(), 'Shift+S'),
'code': (LocaleKeys.toolbar_inlineCode.tr(), 'E'),
};
final markdownItemIds = markdownItemTooltips.keys.toSet();
// the items without shortcuts
if (!markdownItemIds.contains(id)) {
return TextSpan(
text: message,
style: context.tooltipTextStyle(),
);
}
final tooltip = markdownItemTooltips[id];
if (tooltip == null) {
return TextSpan(
text: message,
style: context.tooltipTextStyle(),
);
}
final textSpan = TextSpan(
children: [
TextSpan(
text: '${tooltip.$1}\n',
style: context.tooltipTextStyle(),
),
TextSpan(
text: (Platform.isMacOS ? '⌘+' : 'Ctrl+\\') + tooltip.$2,
style: context
.tooltipTextStyle()
?.copyWith(color: Theme.of(context).hintColor),
),
],
);
return textSpan;
}
}

View File

@ -0,0 +1,26 @@
import 'package:appflowy/util/theme_extension.dart';
import 'package:flutter/material.dart';
extension PickerColors on BuildContext {
Color get pickerTextColor {
return Theme.of(this).isLightMode
? const Color(0x80171717)
: Colors.white.withOpacity(0.5);
}
Color get pickerIconColor {
return Theme.of(this).isLightMode ? const Color(0xFF171717) : Colors.white;
}
Color get pickerSearchBarBorderColor {
return Theme.of(this).isLightMode
? const Color(0x1E171717)
: Colors.white.withOpacity(0.12);
}
Color get pickerButtonBoarderColor {
return Theme.of(this).isLightMode
? const Color(0x1E171717)
: Colors.white.withOpacity(0.12);
}
}

View File

@ -1,12 +1,14 @@
import 'package:appflowy/generated/flowy_svgs.g.dart';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/plugins/base/emoji/emoji_skin_tone.dart';
import 'package:appflowy/shared/icon_emoji_picker/emoji_skin_tone.dart';
import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flutter/material.dart';
import 'package:flutter_emoji_mart/flutter_emoji_mart.dart';
import 'colors.dart';
typedef EmojiKeywordChangedCallback = void Function(String keyword);
typedef EmojiSkinToneChanged = void Function(EmojiSkinTone skinTone);
@ -82,7 +84,7 @@ class _RandomEmojiButton extends StatelessWidget {
height: 36,
decoration: ShapeDecoration(
shape: RoundedRectangleBorder(
side: const BorderSide(color: Color(0x1E171717)),
side: BorderSide(color: context.pickerButtonBoarderColor),
borderRadius: BorderRadius.circular(8),
),
),
@ -141,7 +143,7 @@ class _SearchTextFieldState extends State<_SearchTextField> {
fontWeight: FontWeight.w400,
color: Theme.of(context).hintColor,
),
enableBorderColor: const Color(0x1E171717),
enableBorderColor: context.pickerSearchBarBorderColor,
controller: controller,
onChanged: widget.onKeywordChanged,
prefixIcon: const Padding(

View File

@ -5,6 +5,8 @@ import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flutter/material.dart';
import 'package:flutter_emoji_mart/flutter_emoji_mart.dart';
import 'colors.dart';
// use a temporary global value to store last selected skin tone
EmojiSkinTone? lastSelectedEmojiSkinTone;
@ -68,7 +70,7 @@ class _FlowyEmojiSkinToneSelectorState
width: 36,
height: 36,
decoration: BoxDecoration(
border: Border.all(color: const Color(0x1E171717)),
border: Border.all(color: context.pickerButtonBoarderColor),
borderRadius: BorderRadius.circular(8),
),
child: FlowyButton(

View File

@ -13,6 +13,7 @@ import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flutter/material.dart' hide Icon;
import 'package:flutter/services.dart';
import 'colors.dart';
import 'icon_color_picker.dart';
// cache the icon groups to avoid loading them multiple times
@ -200,7 +201,7 @@ class _IconPickerState extends State<IconPicker> {
iconGroup.displayName,
fontSize: 12,
figmaLineHeight: 18.0,
color: const Color(0x80171717),
color: context.pickerTextColor,
),
const VSpace(4.0),
Wrap(
@ -252,7 +253,7 @@ class _Icon extends StatelessWidget {
child: FlowySvg.string(
icon.content,
size: const Size.square(20),
color: const Color(0xFF171717),
color: context.pickerIconColor,
opacity: 0.7,
),
),

View File

@ -6,6 +6,8 @@ import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flutter/material.dart';
import 'package:flutter_emoji_mart/flutter_emoji_mart.dart';
import 'colors.dart';
typedef IconKeywordChangedCallback = void Function(String keyword);
typedef EmojiSkinToneChanged = void Function(EmojiSkinTone skinTone);
@ -70,7 +72,7 @@ class _RandomIconButton extends StatelessWidget {
height: 36,
decoration: ShapeDecoration(
shape: RoundedRectangleBorder(
side: const BorderSide(color: Color(0x1E171717)),
side: BorderSide(color: context.pickerButtonBoarderColor),
borderRadius: BorderRadius.circular(8),
),
),
@ -123,7 +125,7 @@ class _SearchTextFieldState extends State<_SearchTextField> {
fontWeight: FontWeight.w400,
color: Theme.of(context).hintColor,
),
enableBorderColor: const Color(0x1E171717),
enableBorderColor: context.pickerSearchBarBorderColor,
controller: controller,
onChanged: widget.onKeywordChanged,
prefixIcon: const Padding(

View File

@ -10,6 +10,7 @@ class FlowyTooltip extends StatelessWidget {
this.preferBelow,
this.showDuration,
this.margin,
this.verticalOffset,
this.child,
});
@ -19,6 +20,7 @@ class FlowyTooltip extends StatelessWidget {
final Duration? showDuration;
final EdgeInsetsGeometry? margin;
final Widget? child;
final double? verticalOffset;
@override
Widget build(BuildContext context) {
@ -28,16 +30,14 @@ class FlowyTooltip extends StatelessWidget {
return Tooltip(
margin: margin,
verticalOffset: 16.0,
padding: const EdgeInsets.only(
left: 12.0,
right: 12.0,
top: 5.0,
bottom: 8.0,
verticalOffset: verticalOffset ?? 16.0,
padding: const EdgeInsets.symmetric(
horizontal: 12.0,
vertical: 8.0,
),
decoration: BoxDecoration(
color: context.tooltipBackgroundColor(),
borderRadius: BorderRadius.circular(12.0),
borderRadius: BorderRadius.circular(10.0),
),
waitDuration: _tooltipWaitDuration,
message: message,
@ -50,7 +50,7 @@ class FlowyTooltip extends StatelessWidget {
}
extension FlowyToolTipExtension on BuildContext {
double tooltipFontSize() => 13.0;
double tooltipFontSize() => 14.0;
double tooltipHeight() => 18.0 / tooltipFontSize();
Color tooltipFontColor() => Theme.of(this).brightness == Brightness.light
? Colors.white

View File

@ -53,8 +53,8 @@ packages:
dependency: "direct main"
description:
path: "."
ref: c064543
resolved-ref: c064543e0e40f862f1db2db36725d48465a8aea5
ref: "4536488faf458ab45e304c1715850d4d1ae517ee"
resolved-ref: "4536488faf458ab45e304c1715850d4d1ae517ee"
url: "https://github.com/AppFlowy-IO/appflowy-editor.git"
source: git
version: "3.1.0"

View File

@ -199,7 +199,7 @@ dependency_overrides:
appflowy_editor:
git:
url: https://github.com/AppFlowy-IO/appflowy-editor.git
ref: "c064543"
ref: "4536488faf458ab45e304c1715850d4d1ae517ee"
appflowy_editor_plugins:
git: