Skip to content

Commit

Permalink
feat(neon_rich_text): Render markdown
Browse files Browse the repository at this point in the history
Signed-off-by: provokateurin <kate@provokateurin.de>
  • Loading branch information
provokateurin committed Dec 8, 2024
1 parent 99e02f9 commit 5f94b6f
Show file tree
Hide file tree
Showing 10 changed files with 648 additions and 60 deletions.
541 changes: 514 additions & 27 deletions packages/neon_framework/packages/neon_rich_text/lib/src/rich_text.dart

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions packages/neon_framework/packages/neon_rich_text/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ dependencies:
sdk: flutter
flutter_material_design_icons: ^1.1.7296
intersperse: ^2.0.0
logging: ^1.0.0
markdown: ^7.0.0
meta: ^1.0.0
neon_framework:
git:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mocktail/mocktail.dart';
import 'package:neon_framework/testing.dart';
import 'package:neon_rich_text/neon_rich_text.dart';
import 'package:nextcloud/core.dart' as core;

Expand All @@ -15,19 +16,23 @@ void main() {
group('buildRichTextSpan', () {
test('Preview without newlines', () {
var span = buildRichTextSpan(
account: MockAccount(),
text: '123\n456',
isMarkdown: false,
parameters: BuiltMap(),
references: BuiltList(),
style: const TextStyle(),
textStyle: const TextStyle(),
onReferenceClicked: (_) {},
).children!.single as TextSpan;
expect(span.text, '123\n456');

span = buildRichTextSpan(
account: MockAccount(),
text: '123\n456',
isMarkdown: false,
parameters: BuiltMap(),
references: BuiltList(),
style: const TextStyle(),
textStyle: const TextStyle(),
onReferenceClicked: (_) {},
isPreview: true,
).children!.single as TextSpan;
Expand All @@ -38,7 +43,9 @@ void main() {
for (final type in core.RichObjectParameter_Type.values) {
test(type, () {
final spans = buildRichTextSpan(
account: MockAccount(),
text: 'test',
isMarkdown: false,
parameters: BuiltMap({
type.value: BuiltMap<String, JsonObject>({
'type': JsonObject(type.value),
Expand All @@ -47,7 +54,7 @@ void main() {
}),
}),
references: BuiltList(),
style: const TextStyle(),
textStyle: const TextStyle(),
onReferenceClicked: (_) {},
).children!;
if (type == core.RichObjectParameter_Type.file) {
Expand All @@ -64,7 +71,9 @@ void main() {

test('Used parameters', () {
final spans = buildRichTextSpan(
account: MockAccount(),
text: '123 {actor1} 456 {actor2} 789',
isMarkdown: false,
parameters: BuiltMap({
'actor1': BuiltMap<String, JsonObject>({
'type': JsonObject('user'),
Expand All @@ -78,7 +87,7 @@ void main() {
}),
}),
references: BuiltList(),
style: const TextStyle(),
textStyle: const TextStyle(),
onReferenceClicked: (_) {},
).children!;
expect(spans, hasLength(5));
Expand All @@ -93,10 +102,12 @@ void main() {
final callback = MockOnReferenceClickedCallback();

final spans = buildRichTextSpan(
account: MockAccount(),
text: 'a 123 b 456 c',
isMarkdown: false,
parameters: BuiltMap(),
references: BuiltList(['123', '456']),
style: const TextStyle(),
textStyle: const TextStyle(),
onReferenceClicked: callback.call,
).children!;
expect(spans, hasLength(5));
Expand All @@ -120,7 +131,9 @@ void main() {

test('Skip empty parts', () {
final spans = buildRichTextSpan(
account: MockAccount(),
text: '{actor}',
isMarkdown: false,
parameters: BuiltMap({
'actor': BuiltMap<String, JsonObject>({
'type': JsonObject(core.RichObjectParameter_Type.user.name),
Expand All @@ -129,7 +142,7 @@ void main() {
}),
}),
references: BuiltList(),
style: const TextStyle(),
textStyle: const TextStyle(),
onReferenceClicked: (_) {},
).children!;
expect(spans, hasLength(1));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,12 @@ class NotificationsNotification extends StatelessWidget {
final subject = notification.subjectRichParameters!.isNotEmpty
? Text.rich(
buildRichTextSpan(
account: NeonProvider.of<Account>(context),
text: notification.subjectRich!,
isMarkdown: false,
parameters: notification.subjectRichParameters!,
references: BuiltList(),
style: Theme.of(context).textTheme.bodyLarge!,
textStyle: Theme.of(context).textTheme.bodyLarge!,
onReferenceClicked: (_) {},
),
)
Expand All @@ -38,10 +40,12 @@ class NotificationsNotification extends StatelessWidget {
final message = notification.messageRichParameters!.isNotEmpty
? Text.rich(
buildRichTextSpan(
account: NeonProvider.of<Account>(context),
text: notification.messageRich!,
isMarkdown: false,
parameters: notification.messageRichParameters!,
references: BuiltList(),
style: Theme.of(context).textTheme.bodyMedium!,
textStyle: Theme.of(context).textTheme.bodyMedium!,
onReferenceClicked: (_) {},
),
overflow: TextOverflow.ellipsis,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,11 +84,13 @@ class TalkMessagePreview extends StatelessWidget {
),
),
buildRichTextSpan(
account: NeonProvider.of<Account>(context),
text: chatMessage.message,
isMarkdown: false,
parameters: chatMessage.messageParameters,
references: BuiltList(),
isPreview: true,
style: Theme.of(context).textTheme.bodyMedium!,
textStyle: Theme.of(context).textTheme.bodyMedium!,
onReferenceClicked: (url) async => launchUrl(NeonProvider.of<Account>(context), url),
),
],
Expand Down Expand Up @@ -175,10 +177,12 @@ class TalkSystemMessage extends StatelessWidget {
child: Center(
child: RichText(
text: buildRichTextSpan(
account: NeonProvider.of<Account>(context),
text: chatMessage.message,
isMarkdown: chatMessage.markdown,
parameters: chatMessage.messageParameters,
references: BuiltList(),
style: Theme.of(context).textTheme.labelSmall!,
textStyle: Theme.of(context).textTheme.labelSmall!,
onReferenceClicked: (url) async => launchUrl(NeonProvider.of<Account>(context), url),
),
),
Expand Down Expand Up @@ -378,11 +382,13 @@ class _TalkCommentMessageState extends State<TalkCommentMessage> {

Widget text = Text.rich(
buildRichTextSpan(
account: NeonProvider.of<Account>(context),
text: widget.chatMessage.message,
isMarkdown: widget.chatMessage.markdown && !widget.isParent,
parameters: widget.chatMessage.messageParameters,
isPreview: widget.isParent,
references: references.keys.toBuiltList(),
style: textTheme.bodyLarge!.copyWith(
textStyle: textTheme.bodyLarge!.copyWith(
color: widget.isParent || widget.chatMessage.messageType == spreed.MessageType.commentDeleted
? labelColor
: null,
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,7 @@ void main() {
when(() => chatMessage.actorDisplayName).thenReturn('test');
when(() => chatMessage.message).thenReturn('message');
when(() => chatMessage.messageParameters).thenReturn(BuiltMap());
when(() => chatMessage.markdown).thenReturn(false);

replyTo.add(chatMessage);
await tester.pumpAndSettle();
Expand Down Expand Up @@ -315,6 +316,7 @@ void main() {
when(() => chatMessage.actorDisplayName).thenReturn('test');
when(() => chatMessage.message).thenReturn('message');
when(() => chatMessage.messageParameters).thenReturn(BuiltMap());
when(() => chatMessage.markdown).thenReturn(false);

editing.add(chatMessage);
await tester.pumpAndSettle();
Expand Down
Loading

0 comments on commit 5f94b6f

Please sign in to comment.