editor_style.dart 7.3 KB

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