editor_style.dart 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  1. import 'package:appflowy/plugins/document/presentation/editor_plugins/inline_math_equation/inline_math_equation.dart';
  2. import 'package:appflowy/plugins/document/presentation/editor_plugins/inline_page/inline_page_reference.dart';
  3. import 'package:appflowy/plugins/document/presentation/editor_plugins/mention/mention_block.dart';
  4. import 'package:appflowy/plugins/document/presentation/more/cubit/document_appearance_cubit.dart';
  5. import 'package:appflowy/util/google_font_family_extension.dart';
  6. import 'package:appflowy_editor/appflowy_editor.dart' hide Log;
  7. import 'package:collection/collection.dart';
  8. import 'package:flutter/material.dart';
  9. import 'package:flutter_bloc/flutter_bloc.dart';
  10. import 'package:google_fonts/google_fonts.dart';
  11. class EditorStyleCustomizer {
  12. EditorStyleCustomizer({
  13. required this.context,
  14. required this.padding,
  15. });
  16. final BuildContext context;
  17. final EdgeInsets padding;
  18. EditorStyle style() {
  19. if (PlatformExtension.isDesktopOrWeb) {
  20. return desktop();
  21. } else if (PlatformExtension.isMobile) {
  22. return mobile();
  23. }
  24. throw UnimplementedError();
  25. }
  26. EditorStyle desktop() {
  27. final theme = Theme.of(context);
  28. final fontSize = context.read<DocumentAppearanceCubit>().state.fontSize;
  29. final fontFamily = context.read<DocumentAppearanceCubit>().state.fontFamily;
  30. final defaultTextDirection =
  31. context.read<DocumentAppearanceCubit>().state.defaultTextDirection;
  32. return EditorStyle.desktop(
  33. padding: padding,
  34. cursorColor: theme.colorScheme.primary,
  35. defaultTextDirection: defaultTextDirection,
  36. textStyleConfiguration: TextStyleConfiguration(
  37. text: baseTextStyle(fontFamily).copyWith(
  38. fontSize: fontSize,
  39. color: theme.colorScheme.onBackground,
  40. height: 1.5,
  41. ),
  42. bold: baseTextStyle(fontFamily, fontWeight: FontWeight.bold).copyWith(
  43. fontWeight: FontWeight.w600,
  44. ),
  45. italic: baseTextStyle(fontFamily).copyWith(
  46. fontStyle: FontStyle.italic,
  47. ),
  48. underline: baseTextStyle(fontFamily).copyWith(
  49. decoration: TextDecoration.underline,
  50. ),
  51. strikethrough: baseTextStyle(fontFamily).copyWith(
  52. decoration: TextDecoration.lineThrough,
  53. ),
  54. href: baseTextStyle(fontFamily).copyWith(
  55. color: theme.colorScheme.primary,
  56. decoration: TextDecoration.underline,
  57. ),
  58. code: GoogleFonts.robotoMono(
  59. textStyle: baseTextStyle(fontFamily).copyWith(
  60. fontSize: fontSize,
  61. fontWeight: FontWeight.normal,
  62. color: Colors.red,
  63. backgroundColor: theme.colorScheme.inverseSurface,
  64. ),
  65. ),
  66. ),
  67. textSpanDecorator: customizeAttributeDecorator,
  68. );
  69. }
  70. EditorStyle mobile() {
  71. final theme = Theme.of(context);
  72. final fontSize = context.read<DocumentAppearanceCubit>().state.fontSize;
  73. final fontFamily = context.read<DocumentAppearanceCubit>().state.fontFamily;
  74. return EditorStyle.desktop(
  75. padding: padding,
  76. cursorColor: theme.colorScheme.primary,
  77. textStyleConfiguration: TextStyleConfiguration(
  78. text: baseTextStyle(fontFamily).copyWith(
  79. fontSize: fontSize,
  80. color: theme.colorScheme.onBackground,
  81. height: 1.5,
  82. ),
  83. bold: baseTextStyle(fontFamily).copyWith(
  84. fontWeight: FontWeight.w600,
  85. ),
  86. italic: baseTextStyle(fontFamily).copyWith(fontStyle: FontStyle.italic),
  87. underline: baseTextStyle(fontFamily)
  88. .copyWith(decoration: TextDecoration.underline),
  89. strikethrough: baseTextStyle(fontFamily)
  90. .copyWith(decoration: TextDecoration.lineThrough),
  91. href: baseTextStyle(fontFamily).copyWith(
  92. color: theme.colorScheme.primary,
  93. decoration: TextDecoration.underline,
  94. ),
  95. code: GoogleFonts.robotoMono(
  96. textStyle: baseTextStyle(fontFamily).copyWith(
  97. fontSize: fontSize,
  98. fontWeight: FontWeight.normal,
  99. color: Colors.red,
  100. backgroundColor: theme.colorScheme.inverseSurface,
  101. ),
  102. ),
  103. ),
  104. );
  105. }
  106. TextStyle headingStyleBuilder(int level) {
  107. final fontSize = context.read<DocumentAppearanceCubit>().state.fontSize;
  108. final fontSizes = [
  109. fontSize + 16,
  110. fontSize + 12,
  111. fontSize + 8,
  112. fontSize + 4,
  113. fontSize + 2,
  114. fontSize
  115. ];
  116. return TextStyle(
  117. fontSize: fontSizes.elementAtOrNull(level - 1) ?? fontSize,
  118. fontWeight: FontWeight.bold,
  119. );
  120. }
  121. TextStyle codeBlockStyleBuilder() {
  122. final theme = Theme.of(context);
  123. final fontSize = context.read<DocumentAppearanceCubit>().state.fontSize;
  124. final fontFamily = context.read<DocumentAppearanceCubit>().state.fontFamily;
  125. return baseTextStyle(fontFamily).copyWith(
  126. fontSize: fontSize,
  127. height: 1.5,
  128. color: theme.colorScheme.onBackground,
  129. );
  130. }
  131. TextStyle outlineBlockPlaceholderStyleBuilder() {
  132. final theme = Theme.of(context);
  133. final fontSize = context.read<DocumentAppearanceCubit>().state.fontSize;
  134. return TextStyle(
  135. fontFamily: 'poppins',
  136. fontSize: fontSize,
  137. height: 1.5,
  138. color: theme.colorScheme.onBackground.withOpacity(0.6),
  139. );
  140. }
  141. SelectionMenuStyle selectionMenuStyleBuilder() {
  142. final theme = Theme.of(context);
  143. return SelectionMenuStyle(
  144. selectionMenuBackgroundColor: theme.cardColor,
  145. selectionMenuItemTextColor: theme.colorScheme.onBackground,
  146. selectionMenuItemIconColor: theme.colorScheme.onBackground,
  147. selectionMenuItemSelectedIconColor: theme.colorScheme.onSurface,
  148. selectionMenuItemSelectedTextColor: theme.colorScheme.onSurface,
  149. selectionMenuItemSelectedColor: theme.hoverColor,
  150. );
  151. }
  152. FloatingToolbarStyle floatingToolbarStyleBuilder() {
  153. final theme = Theme.of(context);
  154. return FloatingToolbarStyle(
  155. backgroundColor: theme.colorScheme.onTertiary,
  156. );
  157. }
  158. TextStyle baseTextStyle(
  159. String fontFamily, {
  160. FontWeight? fontWeight,
  161. }) {
  162. try {
  163. return GoogleFonts.getFont(
  164. fontFamily,
  165. fontWeight: fontWeight,
  166. );
  167. } on Exception {
  168. return GoogleFonts.getFont('Poppins');
  169. }
  170. }
  171. InlineSpan customizeAttributeDecorator(
  172. BuildContext context,
  173. Node node,
  174. int index,
  175. TextInsert text,
  176. TextSpan textSpan,
  177. ) {
  178. final attributes = text.attributes;
  179. if (attributes == null) {
  180. return textSpan;
  181. }
  182. // try to refresh font here.
  183. if (attributes.fontFamily != null) {
  184. try {
  185. GoogleFonts.getFont(attributes.fontFamily!.parseFontFamilyName());
  186. } catch (e) {
  187. // ignore
  188. }
  189. }
  190. // customize the inline mention block, like inline page
  191. final mention = attributes[MentionBlockKeys.mention] as Map?;
  192. if (mention != null) {
  193. final type = mention[MentionBlockKeys.type];
  194. if (type == MentionType.page.name) {
  195. return WidgetSpan(
  196. alignment: PlaceholderAlignment.middle,
  197. child: MentionBlock(
  198. key: ValueKey(mention[MentionBlockKeys.pageId]),
  199. mention: mention,
  200. ),
  201. );
  202. }
  203. }
  204. // customize the inline math equation block
  205. final formula = attributes[InlineMathEquationKeys.formula] as String?;
  206. if (formula != null) {
  207. return WidgetSpan(
  208. alignment: PlaceholderAlignment.middle,
  209. child: InlineMathEquation(
  210. node: node,
  211. index: index,
  212. formula: formula,
  213. textStyle: style().textStyleConfiguration.text,
  214. ),
  215. );
  216. }
  217. return defaultTextSpanDecoratorForAttribute(
  218. context,
  219. node,
  220. index,
  221. text,
  222. textSpan,
  223. );
  224. }
  225. }