mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
feat: support customizing font and color before typing (#4765)
* fix: bius buttons highlight status * feat: support customizing font family before typing * feat: support customizing text color before typing
This commit is contained in:
parent
e250f780a4
commit
abd08e5e53
@ -72,7 +72,7 @@ class BIUSItems extends StatelessWidget {
|
||||
},
|
||||
icon: icon,
|
||||
isSelected: editorState.isTextDecorationSelected(richTextKey) &&
|
||||
editorState.toggledStyle[richTextKey] != true,
|
||||
editorState.toggledStyle[richTextKey] != false,
|
||||
iconPadding: const EdgeInsets.symmetric(
|
||||
vertical: 14.0,
|
||||
),
|
||||
|
@ -20,6 +20,8 @@ class ColorItem extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final theme = ToolbarColorExtension.of(context);
|
||||
final selectedBackgroundColor = _getBackgroundColor(context);
|
||||
|
||||
return MobileToolbarMenuItemWrapper(
|
||||
size: const Size(82, 52),
|
||||
onTap: () async {
|
||||
@ -42,10 +44,11 @@ class ColorItem extends StatelessWidget {
|
||||
);
|
||||
},
|
||||
icon: FlowySvgs.m_aa_color_s,
|
||||
backgroundColor: theme.toolbarMenuItemBackgroundColor,
|
||||
isSelected: false,
|
||||
backgroundColor:
|
||||
selectedBackgroundColor ?? theme.toolbarMenuItemBackgroundColor,
|
||||
selectedBackgroundColor: selectedBackgroundColor,
|
||||
isSelected: selectedBackgroundColor != null,
|
||||
showRightArrow: true,
|
||||
enable: editorState.selection?.isCollapsed == false,
|
||||
iconPadding: const EdgeInsets.only(
|
||||
top: 14.0,
|
||||
bottom: 14.0,
|
||||
@ -53,4 +56,33 @@ class ColorItem extends StatelessWidget {
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Color? _getBackgroundColor(BuildContext context) {
|
||||
final selection = editorState.selection;
|
||||
if (selection == null) {
|
||||
return null;
|
||||
}
|
||||
String? backgroundColor =
|
||||
editorState.toggledStyle[AppFlowyRichTextKeys.backgroundColor];
|
||||
if (backgroundColor == null) {
|
||||
if (selection.isCollapsed && selection.startIndex != 0) {
|
||||
backgroundColor = editorState.getDeltaAttributeValueInSelection<String>(
|
||||
AppFlowyRichTextKeys.backgroundColor,
|
||||
selection.copyWith(
|
||||
start: selection.start.copyWith(
|
||||
offset: selection.startIndex - 1,
|
||||
),
|
||||
),
|
||||
);
|
||||
} else {
|
||||
backgroundColor = editorState.getDeltaAttributeValueInSelection<String>(
|
||||
AppFlowyRichTextKeys.backgroundColor,
|
||||
);
|
||||
}
|
||||
}
|
||||
if (backgroundColor != null && int.tryParse(backgroundColor) != null) {
|
||||
return Color(int.parse(backgroundColor));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@ -63,16 +63,9 @@ class _TextColorAndBackgroundColorState
|
||||
extends State<_TextColorAndBackgroundColor> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final String? selectedTextColor =
|
||||
widget.editorState.getDeltaAttributeValueInSelection(
|
||||
AppFlowyRichTextKeys.textColor,
|
||||
widget.selection,
|
||||
);
|
||||
final String? selectedTextColor = _getColor(AppFlowyRichTextKeys.textColor);
|
||||
final String? selectedBackgroundColor =
|
||||
widget.editorState.getDeltaAttributeValueInSelection(
|
||||
AppFlowyRichTextKeys.backgroundColor,
|
||||
widget.selection,
|
||||
);
|
||||
_getColor(AppFlowyRichTextKeys.backgroundColor);
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
@ -90,17 +83,25 @@ class _TextColorAndBackgroundColorState
|
||||
selectedColor: selectedTextColor?.tryToColor(),
|
||||
onSelectedColor: (textColor) async {
|
||||
final hex = textColor.alpha == 0 ? null : textColor.toHex();
|
||||
await widget.editorState.formatDelta(
|
||||
widget.selection,
|
||||
{
|
||||
AppFlowyRichTextKeys.textColor: hex,
|
||||
},
|
||||
selectionExtraInfo: {
|
||||
selectionExtraInfoDisableFloatingToolbar: true,
|
||||
selectionExtraInfoDisableMobileToolbarKey: true,
|
||||
selectionExtraInfoDoNotAttachTextService: true,
|
||||
},
|
||||
);
|
||||
final selection = widget.selection;
|
||||
if (selection.isCollapsed) {
|
||||
widget.editorState.updateToggledStyle(
|
||||
AppFlowyRichTextKeys.textColor,
|
||||
hex ?? '',
|
||||
);
|
||||
} else {
|
||||
await widget.editorState.formatDelta(
|
||||
widget.selection,
|
||||
{
|
||||
AppFlowyRichTextKeys.textColor: hex,
|
||||
},
|
||||
selectionExtraInfo: {
|
||||
selectionExtraInfoDisableFloatingToolbar: true,
|
||||
selectionExtraInfoDisableMobileToolbarKey: true,
|
||||
selectionExtraInfoDoNotAttachTextService: true,
|
||||
},
|
||||
);
|
||||
}
|
||||
setState(() {});
|
||||
},
|
||||
),
|
||||
@ -119,23 +120,53 @@ class _TextColorAndBackgroundColorState
|
||||
onSelectedColor: (backgroundColor) async {
|
||||
final hex =
|
||||
backgroundColor.alpha == 0 ? null : backgroundColor.toHex();
|
||||
await widget.editorState.formatDelta(
|
||||
widget.selection,
|
||||
{
|
||||
AppFlowyRichTextKeys.backgroundColor: hex,
|
||||
},
|
||||
selectionExtraInfo: {
|
||||
selectionExtraInfoDisableFloatingToolbar: true,
|
||||
selectionExtraInfoDisableMobileToolbarKey: true,
|
||||
selectionExtraInfoDoNotAttachTextService: true,
|
||||
},
|
||||
);
|
||||
final selection = widget.selection;
|
||||
if (selection.isCollapsed) {
|
||||
widget.editorState.updateToggledStyle(
|
||||
AppFlowyRichTextKeys.backgroundColor,
|
||||
hex ?? '',
|
||||
);
|
||||
} else {
|
||||
await widget.editorState.formatDelta(
|
||||
widget.selection,
|
||||
{
|
||||
AppFlowyRichTextKeys.backgroundColor: hex,
|
||||
},
|
||||
selectionExtraInfo: {
|
||||
selectionExtraInfoDisableFloatingToolbar: true,
|
||||
selectionExtraInfoDisableMobileToolbarKey: true,
|
||||
selectionExtraInfoDoNotAttachTextService: true,
|
||||
},
|
||||
);
|
||||
}
|
||||
setState(() {});
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
String? _getColor(String key) {
|
||||
final selection = widget.selection;
|
||||
String? color = widget.editorState.toggledStyle[key];
|
||||
if (color == null) {
|
||||
if (selection.isCollapsed && selection.startIndex != 0) {
|
||||
color = widget.editorState.getDeltaAttributeValueInSelection<String>(
|
||||
key,
|
||||
selection.copyWith(
|
||||
start: selection.start.copyWith(
|
||||
offset: selection.startIndex - 1,
|
||||
),
|
||||
),
|
||||
);
|
||||
} else {
|
||||
color = widget.editorState.getDeltaAttributeValueInSelection<String>(
|
||||
key,
|
||||
);
|
||||
}
|
||||
}
|
||||
return color;
|
||||
}
|
||||
}
|
||||
|
||||
class _BackgroundColors extends StatelessWidget {
|
||||
|
@ -1,13 +1,12 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:appflowy/mobile/presentation/setting/font/font_picker_screen.dart';
|
||||
import 'package:appflowy/plugins/document/application/document_appearance_cubit.dart';
|
||||
import 'package:appflowy/plugins/document/presentation/editor_plugins/mobile_toolbar_v3/_toolbar_theme.dart';
|
||||
import 'package:appflowy/plugins/document/presentation/editor_plugins/plugins.dart';
|
||||
import 'package:appflowy/util/google_font_family_extension.dart';
|
||||
import 'package:appflowy_editor/appflowy_editor.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:google_fonts/google_fonts.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
@ -23,15 +22,16 @@ class FontFamilyItem extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final theme = ToolbarColorExtension.of(context);
|
||||
final fontFamily = editorState.getDeltaAttributeValueInSelection<String>(
|
||||
AppFlowyRichTextKeys.fontFamily,
|
||||
);
|
||||
final fontFamily = _getCurrentSelectedFontFamilyName();
|
||||
final systemFonFamily =
|
||||
context.read<DocumentAppearanceCubit>().state.fontFamily;
|
||||
return MobileToolbarMenuItemWrapper(
|
||||
size: const Size(144, 52),
|
||||
onTap: () async {
|
||||
final selection = editorState.selection;
|
||||
if (selection == null) {
|
||||
return;
|
||||
}
|
||||
// disable the floating toolbar
|
||||
unawaited(
|
||||
editorState.updateSelectionWithReason(
|
||||
@ -46,12 +46,17 @@ class FontFamilyItem extends StatelessWidget {
|
||||
final newFont = await context
|
||||
.read<GoRouter>()
|
||||
.push<String>(FontPickerScreen.routeName);
|
||||
if (newFont != null && newFont != fontFamily) {
|
||||
await editorState.formatDelta(selection, {
|
||||
AppFlowyRichTextKeys.fontFamily:
|
||||
GoogleFonts.getFont(newFont).fontFamily,
|
||||
});
|
||||
|
||||
// if the selection is not collapsed, apply the font to the selection.
|
||||
if (newFont != null && !selection.isCollapsed) {
|
||||
if (newFont != fontFamily) {
|
||||
await editorState.formatDelta(selection, {
|
||||
AppFlowyRichTextKeys.fontFamily:
|
||||
GoogleFonts.getFont(newFont).fontFamily,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// wait for the font picker screen to be dismissed.
|
||||
Future.delayed(const Duration(milliseconds: 250), () {
|
||||
// highlight the selected text again.
|
||||
@ -62,13 +67,20 @@ class FontFamilyItem extends StatelessWidget {
|
||||
selectionExtraInfoDisableMobileToolbarKey: false,
|
||||
},
|
||||
);
|
||||
// if the selection is collapsed, save the font for the next typing.
|
||||
if (newFont != null && selection.isCollapsed) {
|
||||
editorState.updateToggledStyle(
|
||||
AppFlowyRichTextKeys.fontFamily,
|
||||
GoogleFonts.getFont(newFont).fontFamily,
|
||||
);
|
||||
}
|
||||
});
|
||||
},
|
||||
text: (fontFamily ?? systemFonFamily).parseFontFamilyName(),
|
||||
fontFamily: fontFamily ?? systemFonFamily,
|
||||
backgroundColor: theme.toolbarMenuItemBackgroundColor,
|
||||
isSelected: false,
|
||||
enable: editorState.selection?.isCollapsed == false,
|
||||
enable: true,
|
||||
showRightArrow: true,
|
||||
iconPadding: const EdgeInsets.only(
|
||||
top: 14.0,
|
||||
@ -81,4 +93,28 @@ class FontFamilyItem extends StatelessWidget {
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
String? _getCurrentSelectedFontFamilyName() {
|
||||
final toggleFontFamily =
|
||||
editorState.toggledStyle[AppFlowyRichTextKeys.fontFamily];
|
||||
if (toggleFontFamily is String && toggleFontFamily.isNotEmpty) {
|
||||
return toggleFontFamily;
|
||||
}
|
||||
final selection = editorState.selection;
|
||||
if (selection != null &&
|
||||
selection.isCollapsed &&
|
||||
selection.startIndex != 0) {
|
||||
return editorState.getDeltaAttributeValueInSelection<String>(
|
||||
AppFlowyRichTextKeys.fontFamily,
|
||||
selection.copyWith(
|
||||
start: selection.start.copyWith(
|
||||
offset: selection.startIndex - 1,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
return editorState.getDeltaAttributeValueInSelection<String>(
|
||||
AppFlowyRichTextKeys.fontFamily,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -11,6 +11,7 @@ class MobileToolbarMenuItemWrapper extends StatelessWidget {
|
||||
this.icon,
|
||||
this.text,
|
||||
this.backgroundColor,
|
||||
this.selectedBackgroundColor,
|
||||
this.enable,
|
||||
this.fontFamily,
|
||||
required this.isSelected,
|
||||
@ -40,6 +41,7 @@ class MobileToolbarMenuItemWrapper extends StatelessWidget {
|
||||
final bool showDownArrow;
|
||||
final bool showRightArrow;
|
||||
final Color? backgroundColor;
|
||||
final Color? selectedBackgroundColor;
|
||||
final EdgeInsets textPadding;
|
||||
|
||||
@override
|
||||
@ -90,7 +92,8 @@ class MobileToolbarMenuItemWrapper extends StatelessWidget {
|
||||
alignment: text != null ? Alignment.centerLeft : Alignment.center,
|
||||
decoration: BoxDecoration(
|
||||
color: isSelected
|
||||
? theme.toolbarMenuItemSelectedBackgroundColor
|
||||
? (selectedBackgroundColor ??
|
||||
theme.toolbarMenuItemSelectedBackgroundColor)
|
||||
: backgroundColor,
|
||||
borderRadius: BorderRadius.only(
|
||||
topLeft: enableTopLeftRadius ? radius : Radius.zero,
|
||||
|
Loading…
Reference in New Issue
Block a user