diff --git a/lib/theme.dart b/lib/theme.dart index 92eebd9..87bbde6 100644 --- a/lib/theme.dart +++ b/lib/theme.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:google_fonts/google_fonts.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:surface/providers/config.dart'; @@ -11,7 +12,8 @@ class ThemeSet { ThemeSet({required this.light, required this.dark}); } -Future createAppThemeSet({Color? seedColorOverride, bool? useMaterial3}) async { +Future createAppThemeSet( + {Color? seedColorOverride, bool? useMaterial3}) async { return ThemeSet( light: await createAppTheme(Brightness.light, useMaterial3: useMaterial3), dark: await createAppTheme(Brightness.dark, useMaterial3: useMaterial3), @@ -26,20 +28,24 @@ Future createAppTheme( final prefs = await SharedPreferences.getInstance(); final seedColorString = prefs.getInt(kAppColorSchemeStoreKey); - final seedColor = seedColorString != null ? Color(seedColorString) : Colors.indigo; + final seedColor = + seedColorString != null ? Color(seedColorString) : Colors.indigo; final colorScheme = ColorScheme.fromSeed( seedColor: seedColorOverride ?? seedColor, brightness: brightness, ); - final hasAppBarTransparent = prefs.getBool(kAppbarTransparentStoreKey) ?? false; - final useM3 = useMaterial3 ?? (prefs.getBool(kMaterialYouToggleStoreKey) ?? true); + final hasAppBarTransparent = + prefs.getBool(kAppbarTransparentStoreKey) ?? false; + final useM3 = + useMaterial3 ?? (prefs.getBool(kMaterialYouToggleStoreKey) ?? true); return ThemeData( useMaterial3: useM3, colorScheme: colorScheme, brightness: brightness, + textTheme: GoogleFonts.rubikTextTheme(), iconTheme: IconThemeData( fill: 0, weight: 400, @@ -52,8 +58,10 @@ Future createAppTheme( appBarTheme: AppBarTheme( centerTitle: true, elevation: hasAppBarTransparent ? 0 : null, - backgroundColor: hasAppBarTransparent ? Colors.transparent : colorScheme.primary, - foregroundColor: hasAppBarTransparent ? colorScheme.onSurface : colorScheme.onPrimary, + backgroundColor: + hasAppBarTransparent ? Colors.transparent : colorScheme.primary, + foregroundColor: + hasAppBarTransparent ? colorScheme.onSurface : colorScheme.onPrimary, ), pageTransitionsTheme: PageTransitionsTheme( builders: { diff --git a/lib/widgets/chat/chat_message.dart b/lib/widgets/chat/chat_message.dart index 2653461..1486116 100644 --- a/lib/widgets/chat/chat_message.dart +++ b/lib/widgets/chat/chat_message.dart @@ -110,7 +110,7 @@ class ChatMessage extends StatelessWidget { ? Icon( kBadgesMeta[user!.badges.first.type]?.$2 ?? Symbols.question_mark, - color: kBadgesMeta[user!.badges.first.type]?.$3, + color: kBadgesMeta[user.badges.first.type]?.$3, fill: 1, size: 18, shadows: [ diff --git a/lib/widgets/markdown_content.dart b/lib/widgets/markdown_content.dart index efb7034..ced0efe 100644 --- a/lib/widgets/markdown_content.dart +++ b/lib/widgets/markdown_content.dart @@ -1,5 +1,7 @@ import 'package:dismissible_page/dismissible_page.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_highlight/flutter_highlight.dart'; +import 'package:flutter_highlight/theme_map.dart'; import 'package:flutter_markdown/flutter_markdown.dart'; import 'package:flutter_markdown_latex/flutter_markdown_latex.dart'; import 'package:go_router/go_router.dart'; @@ -75,15 +77,18 @@ class MarkdownTextContent extends StatelessWidget { ), builders: { 'latex': LatexElementBuilder(), + 'code': HighlightBuilder(), }, softLineBreak: true, extensionSet: markdown.ExtensionSet( [ - markdown.CodeBlockSyntax(), - LatexBlockSyntax(), ...markdown.ExtensionSet.gitHubFlavored.blockSyntaxes, + markdown.CodeBlockSyntax(), + markdown.FencedCodeBlockSyntax(), + LatexBlockSyntax(), ], [ + ...markdown.ExtensionSet.gitHubFlavored.inlineSyntaxes, if (isAutoWarp) markdown.LineBreakSyntax(), _UserNameCardInlineSyntax(), _CustomEmoteInlineSyntax(context), @@ -91,7 +96,6 @@ class MarkdownTextContent extends StatelessWidget { markdown.AutolinkExtensionSyntax(), markdown.CodeSyntax(), LatexInlineSyntax(), - ...markdown.ExtensionSet.gitHubFlavored.inlineSyntaxes ], ), onTapLink: (text, href, title) async { @@ -265,3 +269,56 @@ class _CustomEmoteInlineSyntax extends markdown.InlineSyntax { return true; } } + +class HighlightBuilder extends MarkdownElementBuilder { + @override + Widget? visitElementAfterWithContext( + BuildContext context, + markdown.Element element, + TextStyle? preferredStyle, + TextStyle? parentStyle, + ) { + final isDark = Theme.of(context).brightness == Brightness.dark; + + if (element.attributes['class'] == null && + !element.textContent.trim().contains('\n')) { + return Container( + padding: + EdgeInsets.only(top: 0.0, right: 4.0, bottom: 1.75, left: 4.0), + margin: EdgeInsets.symmetric(horizontal: 2.0), + color: Colors.black12, + child: Text( + element.textContent, + style: GoogleFonts.robotoMono(textStyle: preferredStyle), + )); + } else { + var language = 'plaintext'; + final pattern = RegExp(r'^language-(.+)$'); + if (element.attributes['class'] != null && + pattern.hasMatch(element.attributes['class'] ?? '')) { + language = + pattern.firstMatch(element.attributes['class'] ?? '')?.group(1) ?? + 'plaintext'; + } + return ClipRRect( + borderRadius: const BorderRadius.all(Radius.circular(8)), + child: HighlightView( + element.textContent.trim(), + language: language, + theme: { + ...(isDark ? themeMap['a11y-dark']! : themeMap['a11y-light']!), + 'root': (isDark + ? TextStyle( + backgroundColor: Colors.transparent, + color: Color(0xfff8f8f2)) + : TextStyle( + backgroundColor: Colors.transparent, + color: Color(0xff545454))) + }, + padding: EdgeInsets.all(12), + textStyle: GoogleFonts.robotoMono(textStyle: preferredStyle), + ), + ); + } + } +} diff --git a/pubspec.lock b/pubspec.lock index 69ed43b..12a90ee 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -710,6 +710,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.3.0" + flutter_highlight: + dependency: "direct main" + description: + name: flutter_highlight + sha256: "7b96333867aa07e122e245c033b8ad622e4e3a42a1a2372cbb098a2541d8782c" + url: "https://pub.dev" + source: hosted + version: "0.7.0" flutter_inappwebview: dependency: "direct main" description: @@ -957,6 +965,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.3.2" + highlight: + dependency: transitive + description: + name: highlight + sha256: "5353a83ffe3e3eca7df0abfb72dcf3fa66cc56b953728e7113ad4ad88497cf21" + url: "https://pub.dev" + source: hosted + version: "0.7.0" home_widget: dependency: "direct main" description: diff --git a/pubspec.yaml b/pubspec.yaml index 57aff3b..1272135 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -129,6 +129,7 @@ dependencies: drift_flutter: ^0.2.4 local_notifier: ^0.1.6 flutter_markdown_latex: ^0.3.4 + flutter_highlight: ^0.7.0 dev_dependencies: flutter_test: