mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
chore: highlight code block (#5540)
This commit is contained in:
parent
1d23e28eaf
commit
ce1a6e4fca
@ -67,7 +67,19 @@ class ChatBloc extends Bloc<ChatEvent, ChatState> {
|
|||||||
chatId: state.view.id,
|
chatId: state.view.id,
|
||||||
limit: Int64(10),
|
limit: Int64(10),
|
||||||
);
|
);
|
||||||
ChatEventLoadNextMessage(payload).send();
|
ChatEventLoadNextMessage(payload).send().then(
|
||||||
|
(result) {
|
||||||
|
result.fold((list) {
|
||||||
|
if (!isClosed) {
|
||||||
|
final messages =
|
||||||
|
list.messages.map(_createTextMessage).toList();
|
||||||
|
add(ChatEvent.didLoadLatestMessages(messages));
|
||||||
|
}
|
||||||
|
}, (err) {
|
||||||
|
Log.error("Failed to load messages: $err");
|
||||||
|
});
|
||||||
|
},
|
||||||
|
);
|
||||||
},
|
},
|
||||||
startLoadingPrevMessage: () async {
|
startLoadingPrevMessage: () async {
|
||||||
Int64? beforeMessageId;
|
Int64? beforeMessageId;
|
||||||
|
@ -2,6 +2,7 @@ import 'package:appflowy/generated/locale_keys.g.dart';
|
|||||||
import 'package:appflowy/plugins/ai_chat/application/chat_ai_message_bloc.dart';
|
import 'package:appflowy/plugins/ai_chat/application/chat_ai_message_bloc.dart';
|
||||||
import 'package:appflowy/plugins/ai_chat/application/chat_bloc.dart';
|
import 'package:appflowy/plugins/ai_chat/application/chat_bloc.dart';
|
||||||
import 'package:appflowy/plugins/ai_chat/presentation/chat_loading.dart';
|
import 'package:appflowy/plugins/ai_chat/presentation/chat_loading.dart';
|
||||||
|
import 'package:appflowy/util/theme_extension.dart';
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:fixnum/fixnum.dart';
|
import 'package:fixnum/fixnum.dart';
|
||||||
import 'package:flowy_infra/theme_extension.dart';
|
import 'package:flowy_infra/theme_extension.dart';
|
||||||
@ -13,6 +14,8 @@ import 'package:flutter_bloc/flutter_bloc.dart';
|
|||||||
import 'package:flutter_chat_types/flutter_chat_types.dart';
|
import 'package:flutter_chat_types/flutter_chat_types.dart';
|
||||||
import 'package:markdown_widget/markdown_widget.dart';
|
import 'package:markdown_widget/markdown_widget.dart';
|
||||||
|
|
||||||
|
import 'selectable_highlight.dart';
|
||||||
|
|
||||||
class ChatAITextMessageWidget extends StatelessWidget {
|
class ChatAITextMessageWidget extends StatelessWidget {
|
||||||
const ChatAITextMessageWidget({
|
const ChatAITextMessageWidget({
|
||||||
super.key,
|
super.key,
|
||||||
@ -132,17 +135,29 @@ class ChatAITextMessageWidget extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
PreConfig(
|
PreConfig(
|
||||||
|
builder: (code, language) {
|
||||||
|
return ConstrainedBox(
|
||||||
|
constraints: const BoxConstraints(
|
||||||
|
minWidth: 800,
|
||||||
|
),
|
||||||
|
child: ClipRRect(
|
||||||
|
borderRadius: const BorderRadius.all(Radius.circular(6.0)),
|
||||||
|
child: SelectableHighlightView(
|
||||||
|
code,
|
||||||
|
language: language,
|
||||||
|
theme: getHightlineTheme(context),
|
||||||
padding: const EdgeInsets.all(14),
|
padding: const EdgeInsets.all(14),
|
||||||
decoration: BoxDecoration(
|
textStyle: TextStyle(
|
||||||
color: Theme.of(context)
|
color: AFThemeExtension.of(context).textColor,
|
||||||
.colorScheme
|
fontSize: 14,
|
||||||
.surfaceContainerHighest
|
fontWeight: FontWeight.bold,
|
||||||
.withOpacity(0.6),
|
height: 1.5,
|
||||||
borderRadius: const BorderRadius.all(
|
|
||||||
Radius.circular(8.0),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
PConfig(
|
PConfig(
|
||||||
textStyle: TextStyle(
|
textStyle: TextStyle(
|
||||||
color: AFThemeExtension.of(context).textColor,
|
color: AFThemeExtension.of(context).textColor,
|
||||||
@ -168,6 +183,51 @@ class ChatAITextMessageWidget extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Map<String, TextStyle> getHightlineTheme(BuildContext context) {
|
||||||
|
return {
|
||||||
|
'root': TextStyle(
|
||||||
|
color: const Color(0xffabb2bf),
|
||||||
|
backgroundColor:
|
||||||
|
Theme.of(context).isLightMode ? Colors.white : Colors.black38,
|
||||||
|
),
|
||||||
|
'comment':
|
||||||
|
const TextStyle(color: Color(0xff5c6370), fontStyle: FontStyle.italic),
|
||||||
|
'quote':
|
||||||
|
const TextStyle(color: Color(0xff5c6370), fontStyle: FontStyle.italic),
|
||||||
|
'doctag': const TextStyle(color: Color(0xffc678dd)),
|
||||||
|
'keyword': const TextStyle(color: Color(0xffc678dd)),
|
||||||
|
'formula': const TextStyle(color: Color(0xffc678dd)),
|
||||||
|
'section': const TextStyle(color: Color(0xffe06c75)),
|
||||||
|
'name': const TextStyle(color: Color(0xffe06c75)),
|
||||||
|
'selector-tag': const TextStyle(color: Color(0xffe06c75)),
|
||||||
|
'deletion': const TextStyle(color: Color(0xffe06c75)),
|
||||||
|
'subst': const TextStyle(color: Color(0xffe06c75)),
|
||||||
|
'literal': const TextStyle(color: Color(0xff56b6c2)),
|
||||||
|
'string': const TextStyle(color: Color(0xff98c379)),
|
||||||
|
'regexp': const TextStyle(color: Color(0xff98c379)),
|
||||||
|
'addition': const TextStyle(color: Color(0xff98c379)),
|
||||||
|
'attribute': const TextStyle(color: Color(0xff98c379)),
|
||||||
|
'meta-string': const TextStyle(color: Color(0xff98c379)),
|
||||||
|
'built_in': const TextStyle(color: Color(0xffe6c07b)),
|
||||||
|
'attr': const TextStyle(color: Color(0xffd19a66)),
|
||||||
|
'variable': const TextStyle(color: Color(0xffd19a66)),
|
||||||
|
'template-variable': const TextStyle(color: Color(0xffd19a66)),
|
||||||
|
'type': const TextStyle(color: Color(0xffd19a66)),
|
||||||
|
'selector-class': const TextStyle(color: Color(0xffd19a66)),
|
||||||
|
'selector-attr': const TextStyle(color: Color(0xffd19a66)),
|
||||||
|
'selector-pseudo': const TextStyle(color: Color(0xffd19a66)),
|
||||||
|
'number': const TextStyle(color: Color(0xffd19a66)),
|
||||||
|
'symbol': const TextStyle(color: Color(0xff61aeee)),
|
||||||
|
'bullet': const TextStyle(color: Color(0xff61aeee)),
|
||||||
|
'link': const TextStyle(color: Color(0xff61aeee)),
|
||||||
|
'meta': const TextStyle(color: Color(0xff61aeee)),
|
||||||
|
'selector-id': const TextStyle(color: Color(0xff61aeee)),
|
||||||
|
'title': const TextStyle(color: Color(0xff61aeee)),
|
||||||
|
'emphasis': const TextStyle(fontStyle: FontStyle.italic),
|
||||||
|
'strong': const TextStyle(fontWeight: FontWeight.bold),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
class ChatH1Config extends HeadingConfig {
|
class ChatH1Config extends HeadingConfig {
|
||||||
const ChatH1Config({
|
const ChatH1Config({
|
||||||
this.style = const TextStyle(
|
this.style = const TextStyle(
|
||||||
|
@ -0,0 +1,92 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:highlight/highlight.dart';
|
||||||
|
|
||||||
|
/// Highlight Flutter Widget
|
||||||
|
class SelectableHighlightView extends StatelessWidget {
|
||||||
|
SelectableHighlightView(
|
||||||
|
String input, {
|
||||||
|
super.key,
|
||||||
|
this.language,
|
||||||
|
this.theme = const {},
|
||||||
|
this.padding,
|
||||||
|
this.textStyle,
|
||||||
|
int tabSize = 8,
|
||||||
|
}) : source = input.replaceAll('\t', ' ' * tabSize);
|
||||||
|
|
||||||
|
/// The original code to be highlighted
|
||||||
|
final String source;
|
||||||
|
|
||||||
|
/// Highlight language
|
||||||
|
///
|
||||||
|
/// It is recommended to give it a value for performance
|
||||||
|
///
|
||||||
|
/// [All available languages](https://github.com/pd4d10/highlight/tree/master/highlight/lib/languages)
|
||||||
|
final String? language;
|
||||||
|
|
||||||
|
/// Highlight theme
|
||||||
|
///
|
||||||
|
/// [All available themes](https://github.com/pd4d10/highlight/blob/master/flutter_highlight/lib/themes)
|
||||||
|
final Map<String, TextStyle> theme;
|
||||||
|
|
||||||
|
/// Padding
|
||||||
|
final EdgeInsetsGeometry? padding;
|
||||||
|
|
||||||
|
/// Text styles
|
||||||
|
///
|
||||||
|
/// Specify text styles such as font family and font size
|
||||||
|
final TextStyle? textStyle;
|
||||||
|
|
||||||
|
List<TextSpan> _convert(List<Node> nodes) {
|
||||||
|
final List<TextSpan> spans = [];
|
||||||
|
var currentSpans = spans;
|
||||||
|
final List<List<TextSpan>> stack = [];
|
||||||
|
|
||||||
|
// ignore: always_declare_return_types
|
||||||
|
traverse(Node node) {
|
||||||
|
if (node.value != null) {
|
||||||
|
currentSpans.add(
|
||||||
|
node.className == null
|
||||||
|
? TextSpan(text: node.value)
|
||||||
|
: TextSpan(text: node.value, style: theme[node.className!]),
|
||||||
|
);
|
||||||
|
} else if (node.children != null) {
|
||||||
|
final List<TextSpan> tmp = [];
|
||||||
|
currentSpans
|
||||||
|
.add(TextSpan(children: tmp, style: theme[node.className!]));
|
||||||
|
stack.add(currentSpans);
|
||||||
|
currentSpans = tmp;
|
||||||
|
|
||||||
|
for (final n in node.children!) {
|
||||||
|
traverse(n);
|
||||||
|
if (n == node.children!.last) {
|
||||||
|
currentSpans = stack.isEmpty ? spans : stack.removeLast();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (final node in nodes) {
|
||||||
|
traverse(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
return spans;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const _rootKey = 'root';
|
||||||
|
static const _defaultBackgroundColor = Color(0xffffffff);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Container(
|
||||||
|
color: theme[_rootKey]?.backgroundColor ?? _defaultBackgroundColor,
|
||||||
|
padding: padding,
|
||||||
|
child: SelectableText.rich(
|
||||||
|
TextSpan(
|
||||||
|
style: textStyle,
|
||||||
|
children:
|
||||||
|
_convert(highlight.parse(source, language: language).nodes!),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -681,7 +681,7 @@ packages:
|
|||||||
source: git
|
source: git
|
||||||
version: "1.0.2"
|
version: "1.0.2"
|
||||||
flutter_highlight:
|
flutter_highlight:
|
||||||
dependency: transitive
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: flutter_highlight
|
name: flutter_highlight
|
||||||
sha256: "7b96333867aa07e122e245c033b8ad622e4e3a42a1a2372cbb098a2541d8782c"
|
sha256: "7b96333867aa07e122e245c033b8ad622e4e3a42a1a2372cbb098a2541d8782c"
|
||||||
|
@ -149,6 +149,7 @@ dependencies:
|
|||||||
|
|
||||||
# BitsDojo Window for Windows
|
# BitsDojo Window for Windows
|
||||||
bitsdojo_window: ^0.1.6
|
bitsdojo_window: ^0.1.6
|
||||||
|
flutter_highlight: ^0.7.0
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_lints: ^3.0.1
|
flutter_lints: ^3.0.1
|
||||||
|
Loading…
Reference in New Issue
Block a user