Files
Remever/lib/widgets/markdown_text.dart

96 lines
2.5 KiB
Dart

import 'package:flutter/material.dart';
import 'package:remever/common/resources.dart';
class MarkdownText extends StatelessWidget {
final String text;
final TextStyle? baseStyle;
const MarkdownText(this.text, {super.key, this.baseStyle});
@override
Widget build(BuildContext context) {
return SelectableText.rich(
TextSpan(
children: _parseMarkdown(text),
style:
baseStyle ??
const TextStyle(fontSize: 14, color: AppColors.body_text),
),
);
}
List<TextSpan> _parseMarkdown(String text) {
final lines = text.split('\n');
final spans = <TextSpan>[];
for (var line in lines) {
final trimmed = line.trim();
// H1
if (trimmed.startsWith('# ') && trimmed.length > 2) {
spans.add(
TextSpan(
text: '${trimmed.substring(2)}\n',
style: const TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
),
);
continue;
}
// Нумерованный список
if (RegExp(r'^\d+\.\s').hasMatch(trimmed)) {
final match = RegExp(r'^(\d+)\.\s(.+)').firstMatch(trimmed);
if (match != null) {
spans.add(
TextSpan(
text: '${match.group(0)!}\n',
style: const TextStyle(fontSize: 14),
),
);
continue;
}
}
// Маркированный список
if (trimmed.startsWith('') && trimmed.length > 2) {
spans.add(
TextSpan(
text: '${trimmed.substring(2)}\n',
style: const TextStyle(fontSize: 14),
),
);
continue;
}
// Жирный текст
final boldRegex = RegExp(r'\*\*([^*]+)\*\*');
var remaining = line;
var boldProcessed = <TextSpan>[];
int lastEnd = 0;
for (final match in boldRegex.allMatches(line)) {
if (match.start > lastEnd) {
boldProcessed.add(
TextSpan(text: line.substring(lastEnd, match.start)),
);
}
boldProcessed.add(
TextSpan(
text: match.group(1),
style: const TextStyle(fontWeight: FontWeight.bold),
),
);
lastEnd = match.end;
}
if (lastEnd < line.length) {
boldProcessed.add(TextSpan(text: line.substring(lastEnd)));
}
boldProcessed.add(const TextSpan(text: '\n'));
spans.addAll(boldProcessed);
}
return spans;
}
}