editor_style.dart 7.2 KB

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