mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
feat: customizing the background of a block with theme color (#3691)
This commit is contained in:
parent
4fd35d0de4
commit
c6e3c1fd7c
@ -1,4 +1,5 @@
|
||||
import 'package:appflowy/plugins/document/application/doc_bloc.dart';
|
||||
import 'package:appflowy/plugins/document/presentation/editor_plugins/background_color/theme_background_color.dart';
|
||||
import 'package:appflowy/plugins/document/presentation/editor_plugins/image/custom_image_block_component.dart';
|
||||
import 'package:appflowy/plugins/document/presentation/editor_plugins/plugins.dart';
|
||||
import 'package:appflowy/plugins/document/presentation/editor_style.dart';
|
||||
@ -160,6 +161,9 @@ class _AppFlowyEditorPageState extends State<AppFlowyEditorPage> {
|
||||
TableBlockKeys.type,
|
||||
]);
|
||||
AppFlowyRichTextKeys.supportSliced.add(AppFlowyRichTextKeys.fontFamily);
|
||||
|
||||
// customize the dynamic theme color
|
||||
_customizeBlockComponentBackgroundColorDecorator();
|
||||
}
|
||||
|
||||
@override
|
||||
@ -541,4 +545,33 @@ class _AppFlowyEditorPageState extends State<AppFlowyEditorPage> {
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _customizeBlockComponentBackgroundColorDecorator() {
|
||||
blockComponentBackgroundColorDecorator = (Node node, String colorString) {
|
||||
// the color string is from FlowyTint.
|
||||
final tintColor = FlowyTint.values.firstWhereOrNull(
|
||||
(e) => e.id == colorString,
|
||||
);
|
||||
if (tintColor != null) {
|
||||
return tintColor.color(context);
|
||||
}
|
||||
final themeColor = themeBackgroundColors[colorString];
|
||||
if (themeColor != null) {
|
||||
return themeColor.color(context);
|
||||
}
|
||||
|
||||
if (colorString == optionActionColorDefaultColor) {
|
||||
final defaultColor = node.type == CalloutBlockKeys.type
|
||||
? AFThemeExtension.of(context).calloutBGColor
|
||||
: Colors.transparent;
|
||||
return defaultColor;
|
||||
}
|
||||
|
||||
if (colorString == tableCellDefaultColor) {
|
||||
return AFThemeExtension.of(context).tableCellBGColor;
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -10,6 +10,8 @@ import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:styled_widget/styled_widget.dart';
|
||||
|
||||
const optionActionColorDefaultColor = 'appflowy_theme_default_color';
|
||||
|
||||
enum OptionAction {
|
||||
delete,
|
||||
duplicate,
|
||||
@ -251,12 +253,14 @@ class ColorOptionAction extends PopoverActionCell {
|
||||
// reset to default background color
|
||||
FlowyColorOption(
|
||||
color: defaultColor,
|
||||
name: LocaleKeys.document_plugins_optionAction_defaultColor.tr(),
|
||||
i18n: LocaleKeys.document_plugins_optionAction_defaultColor.tr(),
|
||||
id: optionActionColorDefaultColor,
|
||||
),
|
||||
...FlowyTint.values.map(
|
||||
(e) => FlowyColorOption(
|
||||
color: e.color(context),
|
||||
name: e.tintName(AppFlowyEditorLocalizations.current),
|
||||
i18n: e.tintName(AppFlowyEditorLocalizations.current),
|
||||
id: e.id,
|
||||
),
|
||||
),
|
||||
];
|
||||
@ -268,11 +272,10 @@ class ColorOptionAction extends PopoverActionCell {
|
||||
color: Theme.of(context).colorScheme.onBackground,
|
||||
width: 1,
|
||||
),
|
||||
onTap: (color, index) async {
|
||||
onTap: (option, index) async {
|
||||
final transaction = editorState.transaction;
|
||||
final backgroundColor = color.toHex();
|
||||
transaction.updateNode(node, {
|
||||
blockComponentBackgroundColor: backgroundColor,
|
||||
blockComponentBackgroundColor: option.id,
|
||||
});
|
||||
await editorState.apply(transaction);
|
||||
|
||||
|
@ -0,0 +1,15 @@
|
||||
import 'package:flowy_infra/theme_extension.dart';
|
||||
|
||||
// DON'T MODIFY THIS KEY BECAUSE IT'S SAVED IN THE DATABASE!
|
||||
// Used for the block component background color
|
||||
const themeBackgroundColors = {
|
||||
'appflowy_them_color_tint1': FlowyTint.tint1,
|
||||
'appflowy_them_color_tint2': FlowyTint.tint2,
|
||||
'appflowy_them_color_tint3': FlowyTint.tint3,
|
||||
'appflowy_them_color_tint4': FlowyTint.tint4,
|
||||
'appflowy_them_color_tint5': FlowyTint.tint5,
|
||||
'appflowy_them_color_tint6': FlowyTint.tint6,
|
||||
'appflowy_them_color_tint7': FlowyTint.tint7,
|
||||
'appflowy_them_color_tint8': FlowyTint.tint8,
|
||||
'appflowy_them_color_tint9': FlowyTint.tint9,
|
||||
};
|
@ -88,8 +88,7 @@ class CalloutBlockComponentBuilder extends BlockComponentBuilder {
|
||||
bool validate(Node node) =>
|
||||
node.delta != null &&
|
||||
node.children.isEmpty &&
|
||||
node.attributes[CalloutBlockKeys.icon] is String &&
|
||||
node.attributes[CalloutBlockKeys.backgroundColor] is String;
|
||||
node.attributes[CalloutBlockKeys.icon] is String;
|
||||
}
|
||||
|
||||
// the main widget for rendering the callout block
|
||||
@ -117,7 +116,8 @@ class _CalloutBlockComponentWidgetState
|
||||
DefaultSelectableMixin,
|
||||
BlockComponentConfigurable,
|
||||
BlockComponentTextDirectionMixin,
|
||||
BlockComponentAlignMixin {
|
||||
BlockComponentAlignMixin,
|
||||
BlockComponentBackgroundColorMixin {
|
||||
// the key used to forward focus to the richtext child
|
||||
@override
|
||||
final forwardKey = GlobalKey(debugLabel: 'flowy_rich_text');
|
||||
@ -137,11 +137,13 @@ class _CalloutBlockComponentWidgetState
|
||||
@override
|
||||
Node get node => widget.node;
|
||||
|
||||
// get the background color of the note block from the node's attributes
|
||||
@override
|
||||
Color get backgroundColor {
|
||||
final colorString =
|
||||
node.attributes[CalloutBlockKeys.backgroundColor] as String;
|
||||
return colorString.tryToColor() ?? Colors.transparent;
|
||||
final color = super.backgroundColor;
|
||||
if (color == Colors.transparent) {
|
||||
return AFThemeExtension.of(context).calloutBGColor;
|
||||
}
|
||||
return color;
|
||||
}
|
||||
|
||||
// get the emoji of the note block from the node's attributes or default to '📌'
|
||||
|
@ -4,6 +4,7 @@ import 'package:appflowy/plugins/document/presentation/editor_plugins/base/strin
|
||||
import 'package:appflowy_editor/appflowy_editor.dart';
|
||||
import 'package:appflowy_popover/appflowy_popover.dart';
|
||||
import 'package:easy_localization/easy_localization.dart' hide TextDirection;
|
||||
import 'package:flowy_infra/theme_extension.dart';
|
||||
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:highlight/highlight.dart' as highlight;
|
||||
@ -190,7 +191,7 @@ class _CodeBlockComponentWidgetState extends State<CodeBlockComponentWidget>
|
||||
Widget child = Container(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: const BorderRadius.all(Radius.circular(8.0)),
|
||||
color: Colors.grey.withOpacity(0.1),
|
||||
color: AFThemeExtension.of(context).calloutBGColor,
|
||||
),
|
||||
width: MediaQuery.of(context).size.width,
|
||||
child: Column(
|
||||
|
@ -68,23 +68,16 @@ class OutlineBlockWidget extends BlockComponentStatefulWidget {
|
||||
}
|
||||
|
||||
class _OutlineBlockWidgetState extends State<OutlineBlockWidget>
|
||||
with BlockComponentConfigurable, BlockComponentTextDirectionMixin {
|
||||
with
|
||||
BlockComponentConfigurable,
|
||||
BlockComponentTextDirectionMixin,
|
||||
BlockComponentBackgroundColorMixin {
|
||||
@override
|
||||
BlockComponentConfiguration get configuration => widget.configuration;
|
||||
|
||||
@override
|
||||
Node get node => widget.node;
|
||||
|
||||
// get the background color of the note block from the node's attributes
|
||||
Color get backgroundColor {
|
||||
final colorString =
|
||||
node.attributes[OutlineBlockKeys.backgroundColor] as String?;
|
||||
if (colorString == null) {
|
||||
return Colors.transparent;
|
||||
}
|
||||
return colorString.tryToColor() ?? Colors.transparent;
|
||||
}
|
||||
|
||||
@override
|
||||
late EditorState editorState = context.read<EditorState>();
|
||||
late Stream<(TransactionTime, Transaction)> stream =
|
||||
|
@ -11,6 +11,8 @@ import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
||||
import 'package:flowy_infra_ui/style_widget/extension.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
const tableCellDefaultColor = 'appflowy_table_cell_default_color';
|
||||
|
||||
enum TableOptionAction {
|
||||
addAfter,
|
||||
addBefore,
|
||||
@ -119,12 +121,14 @@ class TableColorOptionAction extends PopoverActionCell {
|
||||
// reset to default background color
|
||||
FlowyColorOption(
|
||||
color: defaultColor,
|
||||
name: LocaleKeys.document_plugins_optionAction_defaultColor.tr(),
|
||||
i18n: LocaleKeys.document_plugins_optionAction_defaultColor.tr(),
|
||||
id: tableCellDefaultColor,
|
||||
),
|
||||
...FlowyTint.values.map(
|
||||
(e) => FlowyColorOption(
|
||||
color: e.color(context),
|
||||
name: e.tintName(AppFlowyEditorLocalizations.current),
|
||||
i18n: e.tintName(AppFlowyEditorLocalizations.current),
|
||||
id: e.id,
|
||||
),
|
||||
),
|
||||
];
|
||||
@ -136,8 +140,9 @@ class TableColorOptionAction extends PopoverActionCell {
|
||||
color: Theme.of(context).colorScheme.onBackground,
|
||||
width: 1,
|
||||
),
|
||||
onTap: (color, index) async {
|
||||
final backgroundColor = selectedColor != color ? color.toHex() : "";
|
||||
onTap: (option, index) async {
|
||||
final backgroundColor =
|
||||
selectedColor != option.color ? option.id : '';
|
||||
TableActions.setBgColor(
|
||||
node,
|
||||
position,
|
||||
|
@ -1,14 +1,15 @@
|
||||
import 'dart:async';
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:appflowy/core/notification/user_notification.dart';
|
||||
import 'package:appflowy_backend/log.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-user/auth.pb.dart';
|
||||
import 'package:dartz/dartz.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
|
||||
import 'dart:typed_data';
|
||||
import 'package:appflowy_backend/protobuf/flowy-notification/protobuf.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-user/auth.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-user/notification.pb.dart'
|
||||
as user;
|
||||
import 'package:appflowy_backend/rust_stream.dart';
|
||||
import 'package:dartz/dartz.dart';
|
||||
|
||||
class UserAuthStateListener {
|
||||
void Function(String)? _onInvalidAuth;
|
||||
|
@ -204,4 +204,28 @@ enum FlowyTint {
|
||||
return AFThemeExtension.of(context).tint9;
|
||||
}
|
||||
}
|
||||
|
||||
String get id {
|
||||
switch (this) {
|
||||
// DON'T change this name because it's saved in the database!
|
||||
case FlowyTint.tint1:
|
||||
return 'appflowy_them_color_tint1';
|
||||
case FlowyTint.tint2:
|
||||
return 'appflowy_them_color_tint2';
|
||||
case FlowyTint.tint3:
|
||||
return 'appflowy_them_color_tint3';
|
||||
case FlowyTint.tint4:
|
||||
return 'appflowy_them_color_tint4';
|
||||
case FlowyTint.tint5:
|
||||
return 'appflowy_them_color_tint5';
|
||||
case FlowyTint.tint6:
|
||||
return 'appflowy_them_color_tint6';
|
||||
case FlowyTint.tint7:
|
||||
return 'appflowy_them_color_tint7';
|
||||
case FlowyTint.tint8:
|
||||
return 'appflowy_them_color_tint8';
|
||||
case FlowyTint.tint9:
|
||||
return 'appflowy_them_color_tint9';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5,17 +5,19 @@ import 'package:flutter/material.dart';
|
||||
class FlowyColorOption {
|
||||
const FlowyColorOption({
|
||||
required this.color,
|
||||
required this.name,
|
||||
required this.i18n,
|
||||
required this.id,
|
||||
});
|
||||
|
||||
final Color color;
|
||||
final String name;
|
||||
final String i18n;
|
||||
final String id;
|
||||
}
|
||||
|
||||
class FlowyColorPicker extends StatelessWidget {
|
||||
final List<FlowyColorOption> colors;
|
||||
final Color? selected;
|
||||
final Function(Color color, int index)? onTap;
|
||||
final Function(FlowyColorOption option, int index)? onTap;
|
||||
final double separatorSize;
|
||||
final double iconSize;
|
||||
final double itemHeight;
|
||||
@ -70,11 +72,11 @@ class FlowyColorPicker extends StatelessWidget {
|
||||
return SizedBox(
|
||||
height: itemHeight,
|
||||
child: FlowyButton(
|
||||
text: FlowyText.medium(option.name),
|
||||
text: FlowyText.medium(option.i18n),
|
||||
leftIcon: colorIcon,
|
||||
rightIcon: checkmark,
|
||||
onTap: () {
|
||||
onTap?.call(option.color, i);
|
||||
onTap?.call(option, i);
|
||||
},
|
||||
),
|
||||
);
|
||||
|
@ -193,7 +193,6 @@
|
||||
{
|
||||
"type": "callout",
|
||||
"data": {
|
||||
"bgColor": "#F0F0F0",
|
||||
"delta": [
|
||||
{ "insert": "\nLike AppFlowy? Follow us:\n" },
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user