diff --git a/frontend/app_flowy/packages/appflowy_editor/documentation/customizing.md b/frontend/app_flowy/packages/appflowy_editor/documentation/customizing.md index 0cd1a231df..98acc58f98 100644 --- a/frontend/app_flowy/packages/appflowy_editor/documentation/customizing.md +++ b/frontend/app_flowy/packages/appflowy_editor/documentation/customizing.md @@ -16,7 +16,6 @@ Widget build(BuildContext context) { alignment: Alignment.topCenter, child: AppFlowyEditor( editorState: EditorState.empty(), - editorStyle: EditorStyle.defaultStyle(), shortcutEvents: const [], customBuilders: const {}, ), @@ -93,7 +92,7 @@ ShortcutEventHandler _underscoreToItalicHandler = (editorState, event) { // Delete the previous 'underscore', // update the style of the text surrounded by the two underscores to 'italic', // and update the cursor position. - TransactionBuilder(editorState) + final transaction = editorState.transaction ..deleteText(textNode, firstUnderscore, 1) ..formatText( textNode, @@ -108,8 +107,8 @@ ShortcutEventHandler _underscoreToItalicHandler = (editorState, event) { path: textNode.path, offset: selection.end.offset - 1, ), - ) - ..commit(); + ); + editorState.apply(transaction); return KeyEventResult.handled; }; @@ -125,7 +124,6 @@ Widget build(BuildContext context) { alignment: Alignment.topCenter, child: AppFlowyEditor( editorState: EditorState.empty(), - editorStyle: EditorStyle.defaultStyle(), customBuilders: const {}, shortcutEvents: [ underscoreToItalic, @@ -138,7 +136,7 @@ Widget build(BuildContext context) { ![After](./images/customize_a_shortcut_event_after.gif) -Check out the [complete code](https://github.com/AppFlowy-IO/AppFlowy/blob/main/frontend/app_flowy/packages/appflowy_editor/example/lib/plugin/underscore_to_italic.dart) file of this example. +Check out the [complete code](https://github.com/AppFlowy-IO/AppFlowy/blob/main/frontend/app_flowy/packages/appflowy_editor/lib/src/service/internal_key_event_handlers/markdown_syntax_to_styled_text.dart) file of this example. ## Customizing a Component @@ -156,7 +154,6 @@ Widget build(BuildContext context) { alignment: Alignment.topCenter, child: AppFlowyEditor( editorState: EditorState.empty(), - editorStyle: EditorStyle.defaultStyle(), shortcutEvents: const [], customBuilders: const {}, ), @@ -180,7 +177,7 @@ We'll use `network_image` in this case. And we add `network_image_src` to the `a Then, we create a class that inherits [NodeWidgetBuilder](../lib/src/service/render_plugin_service.dart). As shown in the autoprompt, we need to implement two functions: 1. one returns a widget -2. the other verifies the correctness of the [Node](../lib/src/document/node.dart). +2. the other verifies the correctness of the [Node](../lib/src/core/document/node.dart). ```dart @@ -308,7 +305,7 @@ return AppFlowyEditor( Check out the [complete code](https://github.com/AppFlowy-IO/AppFlowy/blob/main/frontend/app_flowy/packages/appflowy_editor/example/lib/plugin/network_image_node_widget.dart) file of this example. -## Customizing a Theme (New Feature in 0.0.5, Alpha) +## Customizing a Theme (New Feature in 0.0.7) We will use a simple example to illustrate how to quickly customize a theme. @@ -322,7 +319,6 @@ Widget build(BuildContext context) { alignment: Alignment.topCenter, child: AppFlowyEditor( editorState: EditorState.empty(), - editorStyle: EditorStyle.defaultStyle(), shortcutEvents: const [], customBuilders: const {}, ), @@ -338,44 +334,41 @@ At this point, the editor looks like ... Next, we will customize the `EditorStyle`. ```dart -EditorStyle _customizedStyle() { - final editorStyle = EditorStyle.defaultStyle(); - return editorStyle.copyWith( - cursorColor: Colors.white, - selectionColor: Colors.blue.withOpacity(0.3), - textStyle: editorStyle.textStyle.copyWith( - defaultTextStyle: GoogleFonts.poppins().copyWith( - color: Colors.white, - fontSize: 14.0, - ), - defaultPlaceholderTextStyle: GoogleFonts.poppins().copyWith( - color: Colors.white.withOpacity(0.5), - fontSize: 14.0, - ), - bold: const TextStyle(fontWeight: FontWeight.w900), - code: TextStyle( - fontStyle: FontStyle.italic, - color: Colors.red[300], - backgroundColor: Colors.grey.withOpacity(0.3), - ), - highlightColorHex: '0x6FFFEB3B', +ThemeData customizeEditorTheme(BuildContext context) { + final dark = EditorStyle.dark; + final editorStyle = dark.copyWith( + padding: const EdgeInsets.symmetric(vertical: 20, horizontal: 150), + cursorColor: Colors.red.shade600, + selectionColor: Colors.yellow.shade600.withOpacity(0.5), + textStyle: GoogleFonts.poppins().copyWith( + fontSize: 14, + color: Colors.white, ), - pluginStyles: { - 'text/quote': builtInPluginStyle - ..update( - 'textStyle', - (_) { - return (EditorState editorState, Node node) { - return TextStyle( - color: Colors.blue[200], - fontStyle: FontStyle.italic, - fontSize: 12.0, - ); - }; - }, - ), - }, + placeholderTextStyle: GoogleFonts.poppins().copyWith( + fontSize: 14, + color: Colors.grey.shade400, + ), + code: dark.code?.copyWith( + backgroundColor: Colors.lightBlue.shade200, + fontStyle: FontStyle.italic, + ), + highlightColorHex: '0x60FF0000', // red ); + + final quote = QuotedTextPluginStyle.dark.copyWith( + textStyle: (_, __) => GoogleFonts.poppins().copyWith( + fontSize: 14, + color: Colors.blue.shade400, + fontStyle: FontStyle.italic, + fontWeight: FontWeight.w700, + ), + ); + + return Theme.of(context).copyWith(extensions: [ + editorStyle, + ...darkPlguinStyleExtension, + quote, + ]); } ``` @@ -389,7 +382,7 @@ Widget build(BuildContext context) { alignment: Alignment.topCenter, child: AppFlowyEditor( editorState: EditorState.empty(), - editorStyle: _customizedStyle(), + themeData: customizeEditorTheme(context), shortcutEvents: const [], customBuilders: const {}, ), diff --git a/frontend/app_flowy/packages/appflowy_editor/documentation/images/customizing_a_theme_after.png b/frontend/app_flowy/packages/appflowy_editor/documentation/images/customizing_a_theme_after.png index b45d1cad4e..3890829222 100644 Binary files a/frontend/app_flowy/packages/appflowy_editor/documentation/images/customizing_a_theme_after.png and b/frontend/app_flowy/packages/appflowy_editor/documentation/images/customizing_a_theme_after.png differ diff --git a/frontend/app_flowy/packages/appflowy_editor/documentation/images/customizing_a_theme_before.png b/frontend/app_flowy/packages/appflowy_editor/documentation/images/customizing_a_theme_before.png index 2f8a951ee9..8eaac244a5 100644 Binary files a/frontend/app_flowy/packages/appflowy_editor/documentation/images/customizing_a_theme_before.png and b/frontend/app_flowy/packages/appflowy_editor/documentation/images/customizing_a_theme_before.png differ diff --git a/frontend/app_flowy/packages/appflowy_editor/example/lib/main.dart b/frontend/app_flowy/packages/appflowy_editor/example/lib/main.dart index 128f227676..a21d9a8f23 100644 --- a/frontend/app_flowy/packages/appflowy_editor/example/lib/main.dart +++ b/frontend/app_flowy/packages/appflowy_editor/example/lib/main.dart @@ -1,13 +1,14 @@ import 'dart:convert'; import 'dart:io'; -import 'package:example/plugin/code_block_node_widget.dart'; -import 'package:example/plugin/horizontal_rule_node_widget.dart'; -import 'package:example/plugin/tex_block_node_widget.dart'; +import 'package:example/plugin/editor_theme.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; +import 'package:example/plugin/code_block_node_widget.dart'; +import 'package:example/plugin/horizontal_rule_node_widget.dart'; +import 'package:example/plugin/tex_block_node_widget.dart'; import 'package:file_picker/file_picker.dart'; import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:path_provider/path_provider.dart'; @@ -26,22 +27,16 @@ class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { - return MaterialApp( - localizationsDelegates: const [ + return const MaterialApp( + localizationsDelegates: [ GlobalMaterialLocalizations.delegate, GlobalCupertinoLocalizations.delegate, GlobalWidgetsLocalizations.delegate, AppFlowyEditorLocalizations.delegate, ], - supportedLocales: const [Locale('en', 'US')], + supportedLocales: [Locale('en', 'US')], debugShowCheckedModeBanner: false, - theme: ThemeData( - primarySwatch: Colors.blue, - // extensions: [HeadingPluginStyle.light], - ), - darkTheme: ThemeData.dark(), - themeMode: ThemeMode.dark, - home: const MyHomePage(title: 'AppFlowyEditor Example'), + home: MyHomePage(title: 'AppFlowyEditor Example'), ); } } @@ -60,25 +55,13 @@ class _MyHomePageState extends State { bool darkMode = false; Future? _jsonString; + ThemeData? _editorThemeData; + @override Widget build(BuildContext context) { return Scaffold( extendBodyBehindAppBar: true, body: _buildEditor(context), - // body: Center( - // child: ContextMenu(editorState: EditorState.empty(), items: [ - // [ - // ContextMenuItem(name: 'ABCDEFGHIJKLM', onPressed: (editorState) {}), - // ContextMenuItem(name: 'A', onPressed: (editorState) {}), - // ContextMenuItem(name: 'A', onPressed: (editorState) {}) - // ], - // [ - // ContextMenuItem(name: 'B', onPressed: (editorState) {}), - // ContextMenuItem(name: 'B', onPressed: (editorState) {}), - // ContextMenuItem(name: 'B', onPressed: (editorState) {}) - // ] - // ]), - // ), floatingActionButton: _buildExpandableFab(), ); } @@ -92,10 +75,6 @@ class _MyHomePageState extends State { rootBundle.loadString('assets/example.json'), ); } else if (_pageIndex == 1) { - return _buildEditorWithJsonString( - rootBundle.loadString('assets/big_document.json'), - ); - } else if (_pageIndex == 2) { return _buildEditorWithJsonString( Future.value( jsonEncode(EditorState.empty().document.toJson()), @@ -126,32 +105,19 @@ class _MyHomePageState extends State { _editorState!.transactionStream.listen((event) { debugPrint('Transaction: ${event.toJson()}'); }); - final themeData = darkMode - ? ThemeData.dark().copyWith(extensions: [ - HeadingPluginStyle.dark, - CheckboxPluginStyle.dark, - NumberListPluginStyle.dark, - QuotedTextPluginStyle.dark, - BulletedListPluginStyle.dark, - EditorStyle.dark, - ]) - : ThemeData.light().copyWith( - extensions: [ - HeadingPluginStyle.light, - CheckboxPluginStyle.light, - NumberListPluginStyle.light, - QuotedTextPluginStyle.light, - BulletedListPluginStyle.light, - EditorStyle.light, - ], - ); + _editorThemeData ??= Theme.of(context).copyWith(extensions: [ + if (darkMode) ...darkEditorStyleExtension, + if (darkMode) ...darkPlguinStyleExtension, + if (!darkMode) ...lightEditorStyleExtension, + if (!darkMode) ...lightPlguinStyleExtension, + ]); return Container( color: darkMode ? Colors.black : Colors.white, width: MediaQuery.of(context).size.width, child: AppFlowyEditor( editorState: _editorState!, - themeData: themeData, editable: true, + themeData: _editorThemeData, customBuilders: { 'text/code_block': CodeBlockNodeWidgetBuilder(), 'tex': TeXBlockNodeWidgetBuidler(), @@ -190,10 +156,6 @@ class _MyHomePageState extends State { icon: const Icon(Icons.abc), onPressed: () => _switchToPage(1), ), - ActionButton( - icon: const Icon(Icons.abc), - onPressed: () => _switchToPage(2), - ), ActionButton( icon: const Icon(Icons.print), onPressed: () => _exportDocument(_editorState!), @@ -203,13 +165,22 @@ class _MyHomePageState extends State { onPressed: () async => await _importDocument(), ), ActionButton( - icon: const Icon(Icons.color_lens), + icon: const Icon(Icons.dark_mode), onPressed: () { setState(() { darkMode = !darkMode; }); }, ), + ActionButton( + icon: const Icon(Icons.color_lens), + onPressed: () { + setState(() { + _editorThemeData = customizeEditorTheme(context); + darkMode = true; + }); + }, + ), ], ); } @@ -269,6 +240,7 @@ class _MyHomePageState extends State { void _switchToPage(int pageIndex) { if (pageIndex != _pageIndex) { setState(() { + _editorThemeData = null; _editorState = null; _pageIndex = pageIndex; }); diff --git a/frontend/app_flowy/packages/appflowy_editor/example/lib/plugin/editor_theme.dart b/frontend/app_flowy/packages/appflowy_editor/example/lib/plugin/editor_theme.dart new file mode 100644 index 0000000000..65a8f868fa --- /dev/null +++ b/frontend/app_flowy/packages/appflowy_editor/example/lib/plugin/editor_theme.dart @@ -0,0 +1,40 @@ +import 'package:appflowy_editor/appflowy_editor.dart'; +import 'package:flutter/material.dart'; +import 'package:google_fonts/google_fonts.dart'; + +ThemeData customizeEditorTheme(BuildContext context) { + final dark = EditorStyle.dark; + final editorStyle = dark.copyWith( + padding: const EdgeInsets.symmetric(vertical: 20, horizontal: 150), + cursorColor: Colors.red.shade600, + selectionColor: Colors.yellow.shade600.withOpacity(0.5), + textStyle: GoogleFonts.poppins().copyWith( + fontSize: 14, + color: Colors.white, + ), + placeholderTextStyle: GoogleFonts.poppins().copyWith( + fontSize: 14, + color: Colors.grey.shade400, + ), + code: dark.code?.copyWith( + backgroundColor: Colors.lightBlue.shade200, + fontStyle: FontStyle.italic, + ), + highlightColorHex: '0x60FF0000', // red + ); + + final quote = QuotedTextPluginStyle.dark.copyWith( + textStyle: (_, __) => GoogleFonts.poppins().copyWith( + fontSize: 14, + color: Colors.blue.shade400, + fontStyle: FontStyle.italic, + fontWeight: FontWeight.w700, + ), + ); + + return Theme.of(context).copyWith(extensions: [ + editorStyle, + ...darkPlguinStyleExtension, + quote, + ]); +} diff --git a/frontend/app_flowy/packages/appflowy_editor/lib/src/l10n/intl/messages_all.dart b/frontend/app_flowy/packages/appflowy_editor/lib/src/l10n/intl/messages_all.dart index f98e70ad28..16fd7b9b6b 100644 --- a/frontend/app_flowy/packages/appflowy_editor/lib/src/l10n/intl/messages_all.dart +++ b/frontend/app_flowy/packages/appflowy_editor/lib/src/l10n/intl/messages_all.dart @@ -15,6 +15,7 @@ import 'package:intl/intl.dart'; import 'package:intl/message_lookup_by_library.dart'; import 'package:intl/src/intl_helpers.dart'; +import 'messages_bn_BN.dart' as messages_bn_bn; import 'messages_ca.dart' as messages_ca; import 'messages_cs-CZ.dart' as messages_cs_cz; import 'messages_de-DE.dart' as messages_de_de; @@ -39,6 +40,7 @@ import 'messages_zh-TW.dart' as messages_zh_tw; typedef Future LibraryLoader(); Map _deferredLibraries = { + 'bn_BN': () => new Future.value(null), 'ca': () => new Future.value(null), 'cs_CZ': () => new Future.value(null), 'de_DE': () => new Future.value(null), @@ -64,6 +66,8 @@ Map _deferredLibraries = { MessageLookupByLibrary? _findExact(String localeName) { switch (localeName) { + case 'bn_BN': + return messages_bn_bn.messages; case 'ca': return messages_ca.messages; case 'cs_CZ': diff --git a/frontend/app_flowy/packages/appflowy_editor/lib/src/l10n/intl/messages_bn_BN.dart b/frontend/app_flowy/packages/appflowy_editor/lib/src/l10n/intl/messages_bn_BN.dart new file mode 100644 index 0000000000..38e1cae590 --- /dev/null +++ b/frontend/app_flowy/packages/appflowy_editor/lib/src/l10n/intl/messages_bn_BN.dart @@ -0,0 +1,43 @@ +// DO NOT EDIT. This is code generated via package:intl/generate_localized.dart +// This is a library that provides messages for a bn_BN locale. All the +// messages from the main program should be duplicated here with the same +// function name. + +// Ignore issues from commonly used lints in this file. +// ignore_for_file:unnecessary_brace_in_string_interps, unnecessary_new +// ignore_for_file:prefer_single_quotes,comment_references, directives_ordering +// ignore_for_file:annotate_overrides,prefer_generic_function_type_aliases +// ignore_for_file:unused_import, file_names, avoid_escaping_inner_quotes +// ignore_for_file:unnecessary_string_interpolations, unnecessary_string_escapes + +import 'package:intl/intl.dart'; +import 'package:intl/message_lookup_by_library.dart'; + +final messages = new MessageLookup(); + +typedef String MessageIfAbsent(String messageStr, List args); + +class MessageLookup extends MessageLookupByLibrary { + String get localeName => 'bn_BN'; + + final messages = _notInlinedMessages(_notInlinedMessages); + static Map _notInlinedMessages(_) => { + "bold": MessageLookupByLibrary.simpleMessage("বল্ড ফন্ট"), + "bulletedList": MessageLookupByLibrary.simpleMessage("বুলেট তালিকা"), + "checkbox": MessageLookupByLibrary.simpleMessage("চেকবক্স"), + "embedCode": MessageLookupByLibrary.simpleMessage("এম্বেড কোড"), + "heading1": MessageLookupByLibrary.simpleMessage("শিরোনাম 1"), + "heading2": MessageLookupByLibrary.simpleMessage("শিরোনাম 2"), + "heading3": MessageLookupByLibrary.simpleMessage("শিরোনাম 3"), + "highlight": MessageLookupByLibrary.simpleMessage("হাইলাইট"), + "image": MessageLookupByLibrary.simpleMessage("ইমেজ"), + "italic": MessageLookupByLibrary.simpleMessage("ইটালিক ফন্ট"), + "link": MessageLookupByLibrary.simpleMessage("লিঙ্ক"), + "numberedList": + MessageLookupByLibrary.simpleMessage("সংখ্যাযুক্ত তালিকা"), + "quote": MessageLookupByLibrary.simpleMessage("উদ্ধৃতি"), + "strikethrough": MessageLookupByLibrary.simpleMessage("স্ট্রাইকথ্রু"), + "text": MessageLookupByLibrary.simpleMessage("পাঠ্য"), + "underline": MessageLookupByLibrary.simpleMessage("আন্ডারলাইন") + }; +} diff --git a/frontend/app_flowy/packages/appflowy_editor/lib/src/l10n/l10n.dart b/frontend/app_flowy/packages/appflowy_editor/lib/src/l10n/l10n.dart index 7c45b8ae85..0d464022d2 100644 --- a/frontend/app_flowy/packages/appflowy_editor/lib/src/l10n/l10n.dart +++ b/frontend/app_flowy/packages/appflowy_editor/lib/src/l10n/l10n.dart @@ -219,6 +219,7 @@ class AppLocalizationDelegate List get supportedLocales { return const [ Locale.fromSubtags(languageCode: 'en'), + Locale.fromSubtags(languageCode: 'bn', countryCode: 'BN'), Locale.fromSubtags(languageCode: 'ca'), Locale.fromSubtags(languageCode: 'cs', countryCode: 'CZ'), Locale.fromSubtags(languageCode: 'de', countryCode: 'DE'), diff --git a/frontend/app_flowy/packages/appflowy_editor/lib/src/render/style/plugin_styles.dart b/frontend/app_flowy/packages/appflowy_editor/lib/src/render/style/plugin_styles.dart index 832244a64f..44fabea573 100644 --- a/frontend/app_flowy/packages/appflowy_editor/lib/src/render/style/plugin_styles.dart +++ b/frontend/app_flowy/packages/appflowy_editor/lib/src/render/style/plugin_styles.dart @@ -117,7 +117,13 @@ class CheckboxPluginStyle extends ThemeExtension { static final light = CheckboxPluginStyle( padding: (_, __) => const EdgeInsets.symmetric(vertical: 8.0), - textStyle: (editorState, textNode) => const TextStyle(), + textStyle: (editorState, textNode) { + final isCheck = textNode.attributes.check; + return TextStyle( + decoration: isCheck ? TextDecoration.lineThrough : null, + color: isCheck ? Colors.grey.shade400 : null, + ); + }, icon: (editorState, textNode) { final isCheck = textNode.attributes.check; const iconSize = Size.square(20.0); diff --git a/frontend/app_flowy/packages/appflowy_editor/pubspec.yaml b/frontend/app_flowy/packages/appflowy_editor/pubspec.yaml index a778fa8e91..574757cb79 100644 --- a/frontend/app_flowy/packages/appflowy_editor/pubspec.yaml +++ b/frontend/app_flowy/packages/appflowy_editor/pubspec.yaml @@ -1,6 +1,6 @@ name: appflowy_editor description: A highly customizable rich-text editor for Flutter -version: 0.0.6 +version: 0.0.7 homepage: https://github.com/AppFlowy-IO/AppFlowy platforms: