You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
94 lines
2.7 KiB
94 lines
2.7 KiB
import 'package:flutter/material.dart';
|
|
|
|
import '../helpers/link_handler.dart';
|
|
|
|
class TranslatedMessageContent extends StatelessWidget {
|
|
final String displayText;
|
|
final String? originalText;
|
|
final TextStyle style;
|
|
final TextStyle? originalStyle;
|
|
final bool showOriginalFirst;
|
|
|
|
const TranslatedMessageContent({
|
|
super.key,
|
|
required this.displayText,
|
|
required this.style,
|
|
this.originalText,
|
|
this.originalStyle,
|
|
this.showOriginalFirst = true,
|
|
});
|
|
|
|
// A leading `@[Name]` reply mention, with or without a trailing space.
|
|
static final RegExp _mentionPrefix = RegExp(
|
|
r'^@\[([^\]]+)\]\s*(.*)$',
|
|
dotAll: true,
|
|
);
|
|
|
|
Widget _buildText(BuildContext context, String text, TextStyle textStyle) {
|
|
final match = _mentionPrefix.firstMatch(text);
|
|
if (match == null) {
|
|
return LinkHandler.buildLinkifyText(
|
|
context: context,
|
|
text: text,
|
|
style: textStyle,
|
|
);
|
|
}
|
|
final name = match.group(1)!;
|
|
final rest = match.group(2)!;
|
|
final scheme = Theme.of(context).colorScheme;
|
|
return Text.rich(
|
|
TextSpan(
|
|
children: [
|
|
WidgetSpan(
|
|
alignment: PlaceholderAlignment.middle,
|
|
child: Container(
|
|
padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 1),
|
|
decoration: BoxDecoration(
|
|
color: scheme.onSurface.withValues(alpha: 0.14),
|
|
borderRadius: BorderRadius.circular(6),
|
|
),
|
|
child: Text(
|
|
'@$name',
|
|
style: textStyle.copyWith(fontWeight: FontWeight.w500),
|
|
),
|
|
),
|
|
),
|
|
if (rest.isNotEmpty) TextSpan(text: ' $rest'),
|
|
],
|
|
),
|
|
style: textStyle,
|
|
);
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final trimmedDisplay = displayText.trim();
|
|
final trimmedOriginal = originalText?.trim();
|
|
final shouldShowOriginal =
|
|
trimmedOriginal != null &&
|
|
trimmedOriginal.isNotEmpty &&
|
|
trimmedOriginal != trimmedDisplay;
|
|
final effectiveOriginalStyle =
|
|
originalStyle ??
|
|
style.copyWith(fontStyle: FontStyle.italic, fontSize: style.fontSize);
|
|
final originalWidget = shouldShowOriginal
|
|
? _buildText(context, trimmedOriginal, effectiveOriginalStyle)
|
|
: null;
|
|
final translatedWidget = _buildText(context, trimmedDisplay, style);
|
|
|
|
if (!shouldShowOriginal) {
|
|
return translatedWidget;
|
|
}
|
|
|
|
final children = showOriginalFirst
|
|
? [originalWidget!, const SizedBox(height: 6), translatedWidget]
|
|
: [translatedWidget, const SizedBox(height: 6), originalWidget!];
|
|
|
|
return Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: children,
|
|
);
|
|
}
|
|
}
|