feat: customize desktop toolbar style (#519)

This commit is contained in:
q200892907 2023-10-10 03:52:50 -05:00 • committed by GitHub
commit 5155663163
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
17 changed files with 56 additions and 17 deletions

View file

@ -7,10 +7,16 @@ class FloatingToolbarStyle {
const FloatingToolbarStyle({ const FloatingToolbarStyle({
this.backgroundColor = Colors.black, this.backgroundColor = Colors.black,
this.toolbarActiveColor = Colors.lightBlue, this.toolbarActiveColor = Colors.lightBlue,
this.toolbarIconColor = Colors.white,
this.toolbarShadowColor,
this.toolbarElevation = 0,
}); });
final Color backgroundColor; final Color backgroundColor;
final Color toolbarActiveColor; final Color toolbarActiveColor;
final Color toolbarIconColor;
final Color? toolbarShadowColor;
final double toolbarElevation;
} }
/// A floating toolbar that displays at the top of the editor when the selection /// A floating toolbar that displays at the top of the editor when the selection
@ -124,6 +130,7 @@ class _FloatingToolbarState extends State<FloatingToolbar>
} }
final String _debounceKey = 'show the toolbar'; final String _debounceKey = 'show the toolbar';
void _clear() { void _clear() {
Debounce.cancel(_debounceKey); Debounce.cancel(_debounceKey);
@ -181,6 +188,9 @@ class _FloatingToolbarState extends State<FloatingToolbar>
editorState: editorState, editorState: editorState,
backgroundColor: widget.style.backgroundColor, backgroundColor: widget.style.backgroundColor,
toolbarActiveColor: widget.style.toolbarActiveColor, toolbarActiveColor: widget.style.toolbarActiveColor,
toolbarIconColor: widget.style.toolbarIconColor,
toolbarElevation: widget.style.toolbarElevation,
toolbarShadowColor: widget.style.toolbarShadowColor,
textDirection: widget.textDirection ?? Directionality.of(context), textDirection: widget.textDirection ?? Directionality.of(context),
); );
return _toolbarWidget!; return _toolbarWidget!;

View file

@ -15,6 +15,9 @@ class FloatingToolbarWidget extends StatefulWidget {
super.key, super.key,
this.backgroundColor = Colors.black, this.backgroundColor = Colors.black,
required this.toolbarActiveColor, required this.toolbarActiveColor,
this.toolbarIconColor,
this.toolbarElevation = 0,
this.toolbarShadowColor,
required this.items, required this.items,
required this.editorState, required this.editorState,
required this.textDirection, required this.textDirection,
@ -23,6 +26,9 @@ class FloatingToolbarWidget extends StatefulWidget {
final List<ToolbarItem> items; final List<ToolbarItem> items;
final Color backgroundColor; final Color backgroundColor;
final Color toolbarActiveColor; final Color toolbarActiveColor;
final Color? toolbarIconColor;
final double toolbarElevation;
final Color? toolbarShadowColor;
final EditorState editorState; final EditorState editorState;
final TextDirection textDirection; final TextDirection textDirection;
@ -40,6 +46,8 @@ class _FloatingToolbarWidgetState extends State<FloatingToolbarWidget> {
return Material( return Material(
borderRadius: BorderRadius.circular(8.0), borderRadius: BorderRadius.circular(8.0),
color: widget.backgroundColor, color: widget.backgroundColor,
shadowColor: widget.toolbarShadowColor,
elevation: widget.toolbarElevation,
child: Padding( child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 8.0), padding: const EdgeInsets.symmetric(horizontal: 8.0),
child: SizedBox( child: SizedBox(
@ -59,6 +67,7 @@ class _FloatingToolbarWidgetState extends State<FloatingToolbarWidget> {
context, context,
widget.editorState, widget.editorState,
widget.toolbarActiveColor, widget.toolbarActiveColor,
widget.toolbarIconColor,
), ),
), ),
) )

View file

@ -31,7 +31,7 @@ class _AlignmentToolbarItem extends ToolbarItem {
id: 'editor.$id', id: 'editor.$id',
group: 6, group: 6,
isActive: onlyShowInTextType, isActive: onlyShowInTextType,
builder: (context, editorState, highlightColor) { builder: (context, editorState, highlightColor, iconColor) {
final selection = editorState.selection!; final selection = editorState.selection!;
final nodes = editorState.getNodesInSelection(selection); final nodes = editorState.getNodesInSelection(selection);
final isHighlight = nodes.every( final isHighlight = nodes.every(
@ -42,6 +42,7 @@ class _AlignmentToolbarItem extends ToolbarItem {
iconName: 'toolbar/$name', iconName: 'toolbar/$name',
isHighlight: isHighlight, isHighlight: isHighlight,
highlightColor: highlightColor, highlightColor: highlightColor,
iconColor: iconColor,
tooltip: tooltip, tooltip: tooltip,
onPressed: () => editorState.updateNode( onPressed: () => editorState.updateNode(
selection, selection,

View file

@ -4,7 +4,7 @@ final ToolbarItem bulletedListItem = ToolbarItem(
id: 'editor.bulleted_list', id: 'editor.bulleted_list',
group: 3, group: 3,
isActive: onlyShowInSingleSelectionAndTextType, isActive: onlyShowInSingleSelectionAndTextType,
builder: (context, editorState, highlightColor) { builder: (context, editorState, highlightColor, iconColor) {
final selection = editorState.selection!; final selection = editorState.selection!;
final node = editorState.getNodeAtPath(selection.start.path)!; final node = editorState.getNodeAtPath(selection.start.path)!;
final isHighlight = node.type == 'bulleted_list'; final isHighlight = node.type == 'bulleted_list';
@ -12,6 +12,7 @@ final ToolbarItem bulletedListItem = ToolbarItem(
iconName: 'toolbar/bulleted_list', iconName: 'toolbar/bulleted_list',
isHighlight: isHighlight, isHighlight: isHighlight,
highlightColor: highlightColor, highlightColor: highlightColor,
iconColor: iconColor,
tooltip: AppFlowyEditorLocalizations.current.bulletedList, tooltip: AppFlowyEditorLocalizations.current.bulletedList,
onPressed: () => editorState.formatNode( onPressed: () => editorState.formatNode(
selection, selection,

View file

@ -5,7 +5,7 @@ ToolbarItem buildHighlightColorItem({List<ColorOption>? colorOptions}) {
id: 'editor.highlightColor', id: 'editor.highlightColor',
group: 4, group: 4,
isActive: onlyShowInTextType, isActive: onlyShowInTextType,
builder: (context, editorState, highlightColor) { builder: (context, editorState, highlightColor, iconColor) {
String? highlightColorHex; String? highlightColorHex;
final selection = editorState.selection!; final selection = editorState.selection!;
@ -20,6 +20,7 @@ ToolbarItem buildHighlightColorItem({List<ColorOption>? colorOptions}) {
iconName: 'toolbar/highlight_color', iconName: 'toolbar/highlight_color',
isHighlight: isHighlight, isHighlight: isHighlight,
highlightColor: highlightColor, highlightColor: highlightColor,
iconColor: iconColor,
tooltip: AppFlowyEditorLocalizations.current.highlightColor, tooltip: AppFlowyEditorLocalizations.current.highlightColor,
onPressed: () { onPressed: () {
bool showClearButton = false; bool showClearButton = false;

View file

@ -7,7 +7,7 @@ ToolbarItem buildTextColorItem({
id: 'editor.textColor', id: 'editor.textColor',
group: 4, group: 4,
isActive: onlyShowInTextType, isActive: onlyShowInTextType,
builder: (context, editorState, highlightColor) { builder: (context, editorState, highlightColor, iconColor) {
String? textColorHex; String? textColorHex;
final selection = editorState.selection!; final selection = editorState.selection!;
final nodes = editorState.getNodesInSelection(selection); final nodes = editorState.getNodesInSelection(selection);
@ -21,6 +21,7 @@ ToolbarItem buildTextColorItem({
iconName: 'toolbar/text_color', iconName: 'toolbar/text_color',
isHighlight: isHighlight, isHighlight: isHighlight,
highlightColor: highlightColor, highlightColor: highlightColor,
iconColor: iconColor,
tooltip: AppFlowyEditorLocalizations.current.textColor, tooltip: AppFlowyEditorLocalizations.current.textColor,
onPressed: () { onPressed: () {
bool showClearButton = false; bool showClearButton = false;

View file

@ -43,7 +43,7 @@ class _FormatToolbarItem extends ToolbarItem {
id: 'editor.$id', id: 'editor.$id',
group: 2, group: 2,
isActive: onlyShowInTextType, isActive: onlyShowInTextType,
builder: (context, editorState, highlightColor) { builder: (context, editorState, highlightColor, iconColor) {
final selection = editorState.selection!; final selection = editorState.selection!;
final nodes = editorState.getNodesInSelection(selection); final nodes = editorState.getNodesInSelection(selection);
final isHighlight = nodes.allSatisfyInSelection(selection, (delta) { final isHighlight = nodes.allSatisfyInSelection(selection, (delta) {
@ -55,6 +55,7 @@ class _FormatToolbarItem extends ToolbarItem {
iconName: 'toolbar/$name', iconName: 'toolbar/$name',
isHighlight: isHighlight, isHighlight: isHighlight,
highlightColor: highlightColor, highlightColor: highlightColor,
iconColor: iconColor,
tooltip: tooltip, tooltip: tooltip,
onPressed: () => editorState.toggleAttribute(name), onPressed: () => editorState.toggleAttribute(name),
); );

View file

@ -12,7 +12,7 @@ class _HeadingToolbarItem extends ToolbarItem {
id: 'editor.h$level', id: 'editor.h$level',
group: 1, group: 1,
isActive: onlyShowInSingleSelectionAndTextType, isActive: onlyShowInSingleSelectionAndTextType,
builder: (context, editorState, highlightColor) { builder: (context, editorState, highlightColor, iconColor) {
final selection = editorState.selection!; final selection = editorState.selection!;
final node = editorState.getNodeAtPath(selection.start.path)!; final node = editorState.getNodeAtPath(selection.start.path)!;
final isHighlight = final isHighlight =
@ -22,6 +22,7 @@ class _HeadingToolbarItem extends ToolbarItem {
iconName: 'toolbar/h$level', iconName: 'toolbar/h$level',
isHighlight: isHighlight, isHighlight: isHighlight,
highlightColor: highlightColor, highlightColor: highlightColor,
iconColor: iconColor,
tooltip: levelToTooltips(level), tooltip: levelToTooltips(level),
onPressed: () => editorState.formatNode( onPressed: () => editorState.formatNode(
selection, selection,

View file

@ -10,6 +10,7 @@ class SVGIconItemWidget extends StatelessWidget {
this.iconBuilder, this.iconBuilder,
required this.isHighlight, required this.isHighlight,
required this.highlightColor, required this.highlightColor,
this.iconColor,
this.tooltip, this.tooltip,
this.onPressed, this.onPressed,
}); });
@ -20,6 +21,7 @@ class SVGIconItemWidget extends StatelessWidget {
final WidgetBuilder? iconBuilder; final WidgetBuilder? iconBuilder;
final bool isHighlight; final bool isHighlight;
final Color highlightColor; final Color highlightColor;
final Color? iconColor;
final String? tooltip; final String? tooltip;
final VoidCallback? onPressed; final VoidCallback? onPressed;
@ -29,7 +31,7 @@ class SVGIconItemWidget extends StatelessWidget {
? iconBuilder!(context) ? iconBuilder!(context)
: EditorSvg( : EditorSvg(
name: iconName, name: iconName,
color: isHighlight ? highlightColor : null, color: isHighlight ? highlightColor : iconColor,
width: iconSize.width, width: iconSize.width,
height: iconSize.height, height: iconSize.height,
); );

View file

@ -10,7 +10,7 @@ final linkItem = ToolbarItem(
id: 'editor.link', id: 'editor.link',
group: 4, group: 4,
isActive: onlyShowInSingleSelectionAndTextType, isActive: onlyShowInSingleSelectionAndTextType,
builder: (context, editorState, highlightColor) { builder: (context, editorState, highlightColor, iconColor) {
final selection = editorState.selection!; final selection = editorState.selection!;
final nodes = editorState.getNodesInSelection(selection); final nodes = editorState.getNodesInSelection(selection);
final isHref = nodes.allSatisfyInSelection(selection, (delta) { final isHref = nodes.allSatisfyInSelection(selection, (delta) {
@ -23,6 +23,7 @@ final linkItem = ToolbarItem(
iconName: 'toolbar/link', iconName: 'toolbar/link',
isHighlight: isHref, isHighlight: isHref,
highlightColor: highlightColor, highlightColor: highlightColor,
iconColor: iconColor,
tooltip: AppFlowyEditorLocalizations.current.link, tooltip: AppFlowyEditorLocalizations.current.link,
onPressed: () { onPressed: () {
showLinkMenu(context, editorState, selection, isHref); showLinkMenu(context, editorState, selection, isHref);

View file

@ -4,7 +4,7 @@ final ToolbarItem numberedListItem = ToolbarItem(
id: 'editor.numbered_list', id: 'editor.numbered_list',
group: 3, group: 3,
isActive: onlyShowInSingleSelectionAndTextType, isActive: onlyShowInSingleSelectionAndTextType,
builder: (context, editorState, highlightColor) { builder: (context, editorState, highlightColor, iconColor) {
final selection = editorState.selection!; final selection = editorState.selection!;
final node = editorState.getNodeAtPath(selection.start.path)!; final node = editorState.getNodeAtPath(selection.start.path)!;
final isHighlight = node.type == 'numbered_list'; final isHighlight = node.type == 'numbered_list';
@ -12,6 +12,7 @@ final ToolbarItem numberedListItem = ToolbarItem(
iconName: 'toolbar/numbered_list', iconName: 'toolbar/numbered_list',
isHighlight: isHighlight, isHighlight: isHighlight,
highlightColor: highlightColor, highlightColor: highlightColor,
iconColor: iconColor,
tooltip: AppFlowyEditorLocalizations.current.numberedList, tooltip: AppFlowyEditorLocalizations.current.numberedList,
onPressed: () => editorState.formatNode( onPressed: () => editorState.formatNode(
selection, selection,

View file

@ -4,7 +4,7 @@ final ToolbarItem paragraphItem = ToolbarItem(
id: 'editor.paragraph', id: 'editor.paragraph',
group: 1, group: 1,
isActive: onlyShowInSingleSelectionAndTextType, isActive: onlyShowInSingleSelectionAndTextType,
builder: (context, editorState, highlightColor) { builder: (context, editorState, highlightColor, iconColor) {
final selection = editorState.selection!; final selection = editorState.selection!;
final node = editorState.getNodeAtPath(selection.start.path)!; final node = editorState.getNodeAtPath(selection.start.path)!;
final isHighlight = node.type == 'paragraph'; final isHighlight = node.type == 'paragraph';
@ -13,6 +13,7 @@ final ToolbarItem paragraphItem = ToolbarItem(
iconName: 'toolbar/text', iconName: 'toolbar/text',
isHighlight: isHighlight, isHighlight: isHighlight,
highlightColor: highlightColor, highlightColor: highlightColor,
iconColor: iconColor,
tooltip: AppFlowyEditorLocalizations.current.text, tooltip: AppFlowyEditorLocalizations.current.text,
onPressed: () => editorState.formatNode( onPressed: () => editorState.formatNode(
selection, selection,

View file

@ -7,7 +7,7 @@ final ToolbarItem placeholderItem = ToolbarItem(
id: placeholderItemId, id: placeholderItemId,
group: -1, group: -1,
isActive: (editorState) => true, isActive: (editorState) => true,
builder: (_, __, ___) { builder: (_, __, ___, ____) {
return Padding( return Padding(
padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 5), padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 5),
child: Container( child: Container(

View file

@ -4,7 +4,7 @@ final ToolbarItem quoteItem = ToolbarItem(
id: 'editor.quote', id: 'editor.quote',
group: 3, group: 3,
isActive: onlyShowInSingleSelectionAndTextType, isActive: onlyShowInSingleSelectionAndTextType,
builder: (context, editorState, highlightColor) { builder: (context, editorState, highlightColor, iconColor) {
final selection = editorState.selection!; final selection = editorState.selection!;
final node = editorState.getNodeAtPath(selection.start.path)!; final node = editorState.getNodeAtPath(selection.start.path)!;
final isHighlight = node.type == 'quote'; final isHighlight = node.type == 'quote';
@ -12,6 +12,7 @@ final ToolbarItem quoteItem = ToolbarItem(
iconName: 'toolbar/quote', iconName: 'toolbar/quote',
isHighlight: isHighlight, isHighlight: isHighlight,
highlightColor: highlightColor, highlightColor: highlightColor,
iconColor: iconColor,
tooltip: AppFlowyEditorLocalizations.current.quote, tooltip: AppFlowyEditorLocalizations.current.quote,
onPressed: () => editorState.formatNode( onPressed: () => editorState.formatNode(
selection, selection,

View file

@ -31,7 +31,7 @@ class _TextDirectionToolbarItem extends ToolbarItem {
id: 'editor.$id', id: 'editor.$id',
group: 7, group: 7,
isActive: onlyShowInTextType, isActive: onlyShowInTextType,
builder: (context, editorState, highlightColor) { builder: (context, editorState, highlightColor, iconColor) {
final selection = editorState.selection!; final selection = editorState.selection!;
final nodes = editorState.getNodesInSelection(selection); final nodes = editorState.getNodesInSelection(selection);
final isHighlight = nodes.every( final isHighlight = nodes.every(
@ -41,6 +41,7 @@ class _TextDirectionToolbarItem extends ToolbarItem {
iconName: 'toolbar/$iconName', iconName: 'toolbar/$iconName',
isHighlight: isHighlight, isHighlight: isHighlight,
highlightColor: highlightColor, highlightColor: highlightColor,
iconColor: iconColor,
tooltip: tooltip, tooltip: tooltip,
onPressed: () => editorState.updateNode( onPressed: () => editorState.updateNode(
selection, selection,

View file

@ -30,6 +30,7 @@ class ToolbarItem {
BuildContext context, BuildContext context,
EditorState editorState, EditorState editorState,
Color highlightColor, Color highlightColor,
Color? iconColor,
)? builder; )? builder;
// deprecated // deprecated

View file

@ -1,10 +1,9 @@
import 'package:appflowy_editor/src/editor_state.dart';
import 'package:appflowy_editor/src/flutter/overlay.dart'; import 'package:appflowy_editor/src/flutter/overlay.dart';
import 'package:appflowy_editor/src/render/toolbar/toolbar_item.dart'; import 'package:appflowy_editor/src/render/toolbar/toolbar_item.dart';
import 'package:appflowy_editor/src/render/toolbar/toolbar_item_widget.dart'; import 'package:appflowy_editor/src/render/toolbar/toolbar_item_widget.dart';
import 'package:flutter/material.dart' hide Overlay, OverlayEntry; import 'package:flutter/material.dart' hide Overlay, OverlayEntry;
import 'package:appflowy_editor/src/editor_state.dart';
mixin ToolbarMixin<T extends StatefulWidget> on State<T> { mixin ToolbarMixin<T extends StatefulWidget> on State<T> {
void hide(); void hide();
} }
@ -16,6 +15,7 @@ class ToolbarWidget extends StatefulWidget {
required this.layerLink, required this.layerLink,
required this.offset, required this.offset,
required this.highlightColor, required this.highlightColor,
this.iconColor,
required this.items, required this.items,
this.alignment = Alignment.topLeft, this.alignment = Alignment.topLeft,
}) : super(key: key); }) : super(key: key);
@ -24,6 +24,7 @@ class ToolbarWidget extends StatefulWidget {
final LayerLink layerLink; final LayerLink layerLink;
final Offset offset; final Offset offset;
final Color highlightColor; final Color highlightColor;
final Color? iconColor;
final List<ToolbarItem> items; final List<ToolbarItem> items;
@ -46,7 +47,7 @@ class _ToolbarWidgetState extends State<ToolbarWidget> with ToolbarMixin {
showWhenUnlinked: true, showWhenUnlinked: true,
offset: widget.offset, offset: widget.offset,
followerAnchor: widget.alignment, followerAnchor: widget.alignment,
child: _buildToolbar(context, widget.highlightColor), child: _buildToolbar(context, widget.highlightColor, widget.iconColor),
), ),
); );
} }
@ -57,7 +58,11 @@ class _ToolbarWidgetState extends State<ToolbarWidget> with ToolbarMixin {
_listToolbarOverlay = null; _listToolbarOverlay = null;
} }
Widget _buildToolbar(BuildContext context, Color highlightColor) { Widget _buildToolbar(
BuildContext context,
Color highlightColor,
Color? iconColor,
) {
return Material( return Material(
borderRadius: BorderRadius.circular(8.0), borderRadius: BorderRadius.circular(8.0),
child: Padding( child: Padding(
@ -73,6 +78,7 @@ class _ToolbarWidgetState extends State<ToolbarWidget> with ToolbarMixin {
context, context,
widget.editorState, widget.editorState,
highlightColor, highlightColor,
iconColor,
) ?? ) ??
item.itemBuilder?.call(context, widget.editorState) ?? item.itemBuilder?.call(context, widget.editorState) ??
ToolbarItemWidget( ToolbarItemWidget(