chore: Follow up html messages mxc images

This commit is contained in:
Krille 2023-05-22 16:26:43 +02:00
parent c4447adf8c
commit 38db3b35aa
No known key found for this signature in database
1 changed files with 134 additions and 2 deletions

View File

@ -10,6 +10,7 @@ import 'package:matrix/matrix.dart';
import 'package:fluffychat/config/app_config.dart';
import 'package:fluffychat/widgets/avatar.dart';
import 'package:fluffychat/widgets/mxc_image.dart';
import '../../../utils/url_launcher.dart';
class HtmlMessage extends StatelessWidget {
@ -105,6 +106,12 @@ class HtmlMessage extends StatelessWidget {
'th': Style(
border: Border.all(color: textColor, width: 0.5),
),
'li': Style(
// https://github.com/Sub6Resources/flutter_html/issues/1280
// Workaround for list items printed in the same line. This will
// remove the dots/numbers. Hours wasted: 4
display: Display.block,
),
},
extensions: [
UserPillExtension(context, room),
@ -114,6 +121,9 @@ class HtmlMessage extends StatelessWidget {
style: TextStyle(fontSize: fontSize, color: textColor),
),
const TableHtmlExtension(),
SpoilerExtension(textColor: textColor),
const ImageExtension(),
FontColorExtension(),
],
onLinkTap: (url, _, __) => UrlLauncher(context, url).launchUrl(),
onlyRenderTheseTags: const {
@ -163,13 +173,135 @@ class HtmlMessage extends StatelessWidget {
'caption',
'pre',
'span',
// TODO: Implement image extension for Mxc URIs
//'img',
'img',
'details',
'summary'
};
}
class FontColorExtension extends HtmlExtension {
static const String colorAttribute = 'color';
static const String mxColorAttribute = 'data-mx-color';
static const String bgColorAttribute = 'data-mx-bg-color';
@override
Set<String> get supportedTags => {'font', 'span'};
@override
bool matches(ExtensionContext context) {
if (!supportedTags.contains(context.elementName)) return false;
return context.element?.attributes.keys.any(
{
colorAttribute,
mxColorAttribute,
bgColorAttribute,
}.contains,
) ??
false;
}
Color? hexToColor(String? hexCode) {
if (hexCode == null) return null;
if (hexCode.startsWith('#')) hexCode = hexCode.substring(1);
if (hexCode.length == 6) hexCode = 'FF$hexCode';
final colorValue = int.tryParse(hexCode, radix: 16);
return colorValue == null ? null : Color(colorValue);
}
@override
InlineSpan build(
ExtensionContext context,
Map<StyledElement, InlineSpan> Function() parseChildren,
) {
final colorText = context.element?.attributes[colorAttribute] ??
context.element?.attributes[mxColorAttribute];
final bgColor = context.element?.attributes[bgColorAttribute];
return TextSpan(
style: TextStyle(
color: hexToColor(colorText),
backgroundColor: hexToColor(bgColor),
),
text: context.innerHtml,
);
}
}
class ImageExtension extends HtmlExtension {
final double defaultDimension;
const ImageExtension({this.defaultDimension = 64});
@override
Set<String> get supportedTags => {'img'};
@override
InlineSpan build(
ExtensionContext context,
Map<StyledElement, InlineSpan> Function() parseChildren,
) {
final mxcUrl = Uri.tryParse(context.attributes['href'] ?? '');
if (mxcUrl == null || mxcUrl.scheme != 'mxc') {
return TextSpan(text: context.attributes['alt']);
}
final width =
double.tryParse(context.attributes['width'] ?? '') ?? defaultDimension;
final height =
double.tryParse(context.attributes['height'] ?? '') ?? defaultDimension;
return WidgetSpan(
child: MxcImage(
uri: mxcUrl,
width: width,
height: height,
),
);
}
}
class SpoilerExtension extends HtmlExtension {
final Color textColor;
const SpoilerExtension({required this.textColor});
@override
Set<String> get supportedTags => {'span'};
static const String customDataAttribute = 'data-mx-spoiler';
@override
bool matches(ExtensionContext context) {
if (context.elementName != 'span') return false;
return context.element?.attributes.containsKey(customDataAttribute) ??
false;
}
@override
InlineSpan build(
ExtensionContext context,
Map<StyledElement, InlineSpan> Function() parseChildren,
) {
var obscure = true;
return WidgetSpan(
child: StatefulBuilder(
builder: (context, setState) {
return InkWell(
onTap: () => setState(() {
obscure = !obscure;
}),
child: RichText(
text: TextSpan(
style: obscure ? TextStyle(backgroundColor: textColor) : null,
children: parseChildren().values.toList(),
),
),
);
},
),
);
}
}
class MatrixMathExtension extends HtmlExtension {
final TextStyle? style;