feat: customizing the background of a block with theme color (#3691)

This commit is contained in:
Lucas.Xu 2023-10-16 14:11:05 +08:00 committed by GitHub
parent 4fd35d0de4
commit c6e3c1fd7c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 115 additions and 37 deletions

View File

@ -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;
};
}
}

View File

@ -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);

View File

@ -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,
};

View File

@ -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 '📌'

View File

@ -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(

View File

@ -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 =

View File

@ -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,

View File

@ -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;

View File

@ -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';
}
}
}

View File

@ -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);
},
),
);

View File

@ -193,7 +193,6 @@
{
"type": "callout",
"data": {
"bgColor": "#F0F0F0",
"delta": [
{ "insert": "\nLike AppFlowy? Follow us:\n" },
{