feat: customize appflowy editor selection menu style

This commit is contained in:
Lucas.Xu 2022-10-26 10:16:14 +08:00
parent 8656cfeb1e
commit 23a65bfa2a
10 changed files with 123 additions and 31 deletions

View File

@ -39,6 +39,8 @@ class MyApp extends StatelessWidget {
primarySwatch: Colors.blue,
// extensions: [HeadingPluginStyle.light],
),
darkTheme: ThemeData.dark(),
themeMode: ThemeMode.dark,
home: const MyHomePage(title: 'AppFlowyEditor Example'),
);
}

View File

@ -46,7 +46,7 @@ ShortcutEventHandler _ignorekHandler = (editorState, event) {
SelectionMenuItem codeBlockMenuItem = SelectionMenuItem(
name: () => 'Code Block',
icon: const Icon(
icon: (_, __) => const Icon(
Icons.abc,
color: Colors.black,
size: 18.0,

View File

@ -38,7 +38,7 @@ ShortcutEventHandler _insertHorzaontalRule = (editorState, event) {
SelectionMenuItem horizontalRuleMenuItem = SelectionMenuItem(
name: () => 'Horizontal rule',
icon: const Icon(
icon: (_, __) => const Icon(
Icons.horizontal_rule,
color: Colors.black,
size: 18.0,

View File

@ -6,7 +6,7 @@ import 'package:flutter_math_fork/flutter_math.dart';
SelectionMenuItem teXBlockMenuItem = SelectionMenuItem(
name: () => 'Tex',
icon: const Icon(
icon: (_, __) => const Icon(
Icons.text_fields_rounded,
color: Colors.black,
size: 18.0,

View File

@ -3,7 +3,7 @@ import 'package:appflowy_editor/src/render/selection_menu/selection_menu_service
import 'package:appflowy_editor/src/render/selection_menu/selection_menu_widget.dart';
import 'package:flutter/material.dart';
class SelectionMenuItemWidget extends StatelessWidget {
class SelectionMenuItemWidget extends StatefulWidget {
const SelectionMenuItemWidget({
Key? key,
required this.editorState,
@ -11,7 +11,6 @@ class SelectionMenuItemWidget extends StatelessWidget {
required this.item,
required this.isSelected,
this.width = 140.0,
this.selectedColor = const Color(0xFFE0F8FF),
}) : super(key: key);
final EditorState editorState;
@ -19,33 +18,52 @@ class SelectionMenuItemWidget extends StatelessWidget {
final SelectionMenuItem item;
final double width;
final bool isSelected;
final Color selectedColor;
@override
State<SelectionMenuItemWidget> createState() =>
_SelectionMenuItemWidgetState();
}
class _SelectionMenuItemWidgetState extends State<SelectionMenuItemWidget> {
var _onHover = false;
@override
Widget build(BuildContext context) {
final editorStyle = widget.editorState.editorStyle;
return Container(
padding: const EdgeInsets.fromLTRB(8.0, 5.0, 8.0, 5.0),
child: SizedBox(
width: width,
width: widget.width,
child: TextButton.icon(
icon: item.icon,
icon: widget.item
.icon(widget.editorState, widget.isSelected || _onHover),
style: ButtonStyle(
alignment: Alignment.centerLeft,
overlayColor: MaterialStateProperty.all(selectedColor),
backgroundColor: isSelected
? MaterialStateProperty.all(selectedColor)
overlayColor: MaterialStateProperty.all(
editorStyle.selectionMenuItemSelectedColor),
backgroundColor: widget.isSelected
? MaterialStateProperty.all(
editorStyle.selectionMenuItemSelectedColor)
: MaterialStateProperty.all(Colors.transparent),
),
label: Text(
item.name(),
widget.item.name(),
textAlign: TextAlign.left,
style: const TextStyle(
color: Colors.black,
fontSize: 14.0,
style: TextStyle(
color: widget.isSelected || _onHover
? editorStyle.selectionMenuItemSelectedTextColor
: editorStyle.selectionMenuItemTextColor,
fontSize: 12.0,
),
),
onPressed: () {
item.handler(editorState, menuService, context);
widget.item
.handler(widget.editorState, widget.menuService, context);
},
onHover: (value) {
setState(() {
_onHover = value;
});
},
),
),

View File

@ -131,7 +131,8 @@ List<SelectionMenuItem> get defaultSelectionMenuItems =>
final List<SelectionMenuItem> _defaultSelectionMenuItems = [
SelectionMenuItem(
name: () => AppFlowyEditorLocalizations.current.text,
icon: _selectionMenuIcon('text'),
icon: (editorState, onSelected) =>
_selectionMenuIcon('text', editorState, onSelected),
keywords: ['text'],
handler: (editorState, _, __) {
insertTextNodeAfterSelection(editorState, {});
@ -139,7 +140,8 @@ final List<SelectionMenuItem> _defaultSelectionMenuItems = [
),
SelectionMenuItem(
name: () => AppFlowyEditorLocalizations.current.heading1,
icon: _selectionMenuIcon('h1'),
icon: (editorState, onSelected) =>
_selectionMenuIcon('h1', editorState, onSelected),
keywords: ['heading 1, h1'],
handler: (editorState, _, __) {
insertHeadingAfterSelection(editorState, BuiltInAttributeKey.h1);
@ -147,7 +149,8 @@ final List<SelectionMenuItem> _defaultSelectionMenuItems = [
),
SelectionMenuItem(
name: () => AppFlowyEditorLocalizations.current.heading2,
icon: _selectionMenuIcon('h2'),
icon: (editorState, onSelected) =>
_selectionMenuIcon('h2', editorState, onSelected),
keywords: ['heading 2, h2'],
handler: (editorState, _, __) {
insertHeadingAfterSelection(editorState, BuiltInAttributeKey.h2);
@ -155,7 +158,8 @@ final List<SelectionMenuItem> _defaultSelectionMenuItems = [
),
SelectionMenuItem(
name: () => AppFlowyEditorLocalizations.current.heading3,
icon: _selectionMenuIcon('h3'),
icon: (editorState, onSelected) =>
_selectionMenuIcon('h3', editorState, onSelected),
keywords: ['heading 3, h3'],
handler: (editorState, _, __) {
insertHeadingAfterSelection(editorState, BuiltInAttributeKey.h3);
@ -163,13 +167,15 @@ final List<SelectionMenuItem> _defaultSelectionMenuItems = [
),
SelectionMenuItem(
name: () => AppFlowyEditorLocalizations.current.image,
icon: _selectionMenuIcon('image'),
icon: (editorState, onSelected) =>
_selectionMenuIcon('image', editorState, onSelected),
keywords: ['image'],
handler: showImageUploadMenu,
),
SelectionMenuItem(
name: () => AppFlowyEditorLocalizations.current.bulletedList,
icon: _selectionMenuIcon('bulleted_list'),
icon: (editorState, onSelected) =>
_selectionMenuIcon('bulleted_list', editorState, onSelected),
keywords: ['bulleted list', 'list', 'unordered list'],
handler: (editorState, _, __) {
insertBulletedListAfterSelection(editorState);
@ -177,7 +183,8 @@ final List<SelectionMenuItem> _defaultSelectionMenuItems = [
),
SelectionMenuItem(
name: () => AppFlowyEditorLocalizations.current.numberedList,
icon: _selectionMenuIcon('number'),
icon: (editorState, onSelected) =>
_selectionMenuIcon('number', editorState, onSelected),
keywords: ['numbered list', 'list', 'ordered list'],
handler: (editorState, _, __) {
insertNumberedListAfterSelection(editorState);
@ -185,7 +192,8 @@ final List<SelectionMenuItem> _defaultSelectionMenuItems = [
),
SelectionMenuItem(
name: () => AppFlowyEditorLocalizations.current.checkbox,
icon: _selectionMenuIcon('checkbox'),
icon: (editorState, onSelected) =>
_selectionMenuIcon('checkbox', editorState, onSelected),
keywords: ['todo list', 'list', 'checkbox list'],
handler: (editorState, _, __) {
insertCheckboxAfterSelection(editorState);
@ -193,7 +201,8 @@ final List<SelectionMenuItem> _defaultSelectionMenuItems = [
),
SelectionMenuItem(
name: () => AppFlowyEditorLocalizations.current.quote,
icon: _selectionMenuIcon('quote'),
icon: (editorState, onSelected) =>
_selectionMenuIcon('quote', editorState, onSelected),
keywords: ['quote', 'refer'],
handler: (editorState, _, __) {
insertQuoteAfterSelection(editorState);
@ -201,10 +210,13 @@ final List<SelectionMenuItem> _defaultSelectionMenuItems = [
),
];
Widget _selectionMenuIcon(String name) {
Widget _selectionMenuIcon(
String name, EditorState editorState, bool onSelected) {
return FlowySvg(
name: 'selection_menu/$name',
color: Colors.black,
color: onSelected
? editorState.editorStyle.selectionMenuItemSelectedIconColor
: editorState.editorStyle.selectionMenuItemIconColor,
width: 18.0,
height: 18.0,
);

View File

@ -29,7 +29,7 @@ class SelectionMenuItem {
}
final String Function() name;
final Widget icon;
final Widget Function(EditorState editorState, bool onSelected) icon;
/// Customizes keywords for item.
///
@ -142,7 +142,7 @@ class _SelectionMenuWidgetState extends State<SelectionMenuWidget> {
onKey: _onKey,
child: Container(
decoration: BoxDecoration(
color: Colors.white,
color: widget.editorState.editorStyle.selectionMenuBackgroundColor,
boxShadow: [
BoxShadow(
blurRadius: 5,

View File

@ -14,6 +14,14 @@ class EditorStyle extends ThemeExtension<EditorStyle> {
final Color? cursorColor;
final Color? selectionColor;
// Selection menu styles
final Color? selectionMenuBackgroundColor;
final Color? selectionMenuItemTextColor;
final Color? selectionMenuItemIconColor;
final Color? selectionMenuItemSelectedTextColor;
final Color? selectionMenuItemSelectedIconColor;
final Color? selectionMenuItemSelectedColor;
// Text styles
final EdgeInsets? textPadding;
final TextStyle? textStyle;
@ -33,6 +41,12 @@ class EditorStyle extends ThemeExtension<EditorStyle> {
required this.padding,
required this.cursorColor,
required this.selectionColor,
required this.selectionMenuBackgroundColor,
required this.selectionMenuItemTextColor,
required this.selectionMenuItemIconColor,
required this.selectionMenuItemSelectedTextColor,
required this.selectionMenuItemSelectedIconColor,
required this.selectionMenuItemSelectedColor,
required this.textPadding,
required this.textStyle,
required this.placeholderTextStyle,
@ -51,6 +65,12 @@ class EditorStyle extends ThemeExtension<EditorStyle> {
EdgeInsets? padding,
Color? cursorColor,
Color? selectionColor,
Color? selectionMenuBackgroundColor,
Color? selectionMenuItemTextColor,
Color? selectionMenuItemIconColor,
Color? selectionMenuItemSelectedTextColor,
Color? selectionMenuItemSelectedIconColor,
Color? selectionMenuItemSelectedColor,
TextStyle? textStyle,
TextStyle? placeholderTextStyle,
TextStyle? bold,
@ -66,6 +86,18 @@ class EditorStyle extends ThemeExtension<EditorStyle> {
padding: padding ?? this.padding,
cursorColor: cursorColor ?? this.cursorColor,
selectionColor: selectionColor ?? this.selectionColor,
selectionMenuBackgroundColor:
selectionMenuBackgroundColor ?? this.selectionMenuBackgroundColor,
selectionMenuItemTextColor:
selectionMenuItemTextColor ?? this.selectionMenuItemTextColor,
selectionMenuItemIconColor:
selectionMenuItemIconColor ?? this.selectionMenuItemIconColor,
selectionMenuItemSelectedTextColor: selectionMenuItemSelectedTextColor ??
selectionMenuItemSelectedTextColor,
selectionMenuItemSelectedIconColor: selectionMenuItemSelectedIconColor ??
selectionMenuItemSelectedIconColor,
selectionMenuItemSelectedColor:
selectionMenuItemSelectedColor ?? this.selectionMenuItemSelectedColor,
textPadding: textPadding ?? textPadding,
textStyle: textStyle ?? this.textStyle,
placeholderTextStyle: placeholderTextStyle ?? this.placeholderTextStyle,
@ -91,6 +123,22 @@ class EditorStyle extends ThemeExtension<EditorStyle> {
cursorColor: Color.lerp(cursorColor, other.cursorColor, t),
textPadding: EdgeInsets.lerp(textPadding, other.textPadding, t),
selectionColor: Color.lerp(selectionColor, other.selectionColor, t),
selectionMenuBackgroundColor: Color.lerp(
selectionMenuBackgroundColor, other.selectionMenuBackgroundColor, t),
selectionMenuItemTextColor: Color.lerp(
selectionMenuItemTextColor, other.selectionMenuItemTextColor, t),
selectionMenuItemIconColor: Color.lerp(
selectionMenuItemIconColor, other.selectionMenuItemIconColor, t),
selectionMenuItemSelectedTextColor: Color.lerp(
selectionMenuItemSelectedTextColor,
other.selectionMenuItemSelectedTextColor,
t),
selectionMenuItemSelectedIconColor: Color.lerp(
selectionMenuItemSelectedIconColor,
other.selectionMenuItemSelectedIconColor,
t),
selectionMenuItemSelectedColor: Color.lerp(selectionMenuItemSelectedColor,
other.selectionMenuItemSelectedColor, t),
textStyle: TextStyle.lerp(textStyle, other.textStyle, t),
placeholderTextStyle:
TextStyle.lerp(placeholderTextStyle, other.placeholderTextStyle, t),
@ -109,6 +157,12 @@ class EditorStyle extends ThemeExtension<EditorStyle> {
padding: const EdgeInsets.fromLTRB(200.0, 0.0, 200.0, 0.0),
cursorColor: const Color(0xFF00BCF0),
selectionColor: const Color.fromARGB(53, 111, 201, 231),
selectionMenuBackgroundColor: const Color(0xFFFFFFFF),
selectionMenuItemTextColor: const Color(0xFF333333),
selectionMenuItemIconColor: const Color(0xFF333333),
selectionMenuItemSelectedTextColor: const Color(0xFF333333),
selectionMenuItemSelectedIconColor: const Color(0xFF333333),
selectionMenuItemSelectedColor: const Color(0xFFE0F8FF),
textPadding: const EdgeInsets.symmetric(vertical: 8.0),
textStyle: const TextStyle(fontSize: 16.0, color: Colors.black),
placeholderTextStyle: const TextStyle(fontSize: 16.0, color: Colors.grey),
@ -135,5 +189,11 @@ class EditorStyle extends ThemeExtension<EditorStyle> {
fontSize: 16.0,
color: Colors.white.withOpacity(0.3),
),
selectionMenuBackgroundColor: const Color(0xFF282E3A),
selectionMenuItemTextColor: const Color(0xFFBBC3CD),
selectionMenuItemIconColor: const Color(0xFFBBC3CD),
selectionMenuItemSelectedTextColor: const Color(0xFF131720),
selectionMenuItemSelectedIconColor: const Color(0xFF131720),
selectionMenuItemSelectedColor: const Color(0xFF00BCF0),
);
}

View File

@ -137,7 +137,7 @@ Future<EditorWidgetTester> _prepare(WidgetTester tester) async {
);
for (final item in defaultSelectionMenuItems) {
expect(find.byWidget(item.icon), findsOneWidget);
expect(find.text(item.name()), findsOneWidget);
}
return Future.value(editor);

View File

@ -30,7 +30,7 @@ void main() async {
);
for (final item in defaultSelectionMenuItems) {
expect(find.byWidget(item.icon), findsOneWidget);
expect(find.text(item.name()), findsOneWidget);
}
await editor.updateSelection(Selection.single(path: [1], startOffset: 0));