mirror of
https://gitlab.com/famedly/fluffychat.git
synced 2025-02-03 08:44:14 +01:00
chore: Follow up html messages mxc images
This commit is contained in:
parent
c4447adf8c
commit
38db3b35aa
@ -10,6 +10,7 @@ import 'package:matrix/matrix.dart';
|
|||||||
|
|
||||||
import 'package:fluffychat/config/app_config.dart';
|
import 'package:fluffychat/config/app_config.dart';
|
||||||
import 'package:fluffychat/widgets/avatar.dart';
|
import 'package:fluffychat/widgets/avatar.dart';
|
||||||
|
import 'package:fluffychat/widgets/mxc_image.dart';
|
||||||
import '../../../utils/url_launcher.dart';
|
import '../../../utils/url_launcher.dart';
|
||||||
|
|
||||||
class HtmlMessage extends StatelessWidget {
|
class HtmlMessage extends StatelessWidget {
|
||||||
@ -105,6 +106,12 @@ class HtmlMessage extends StatelessWidget {
|
|||||||
'th': Style(
|
'th': Style(
|
||||||
border: Border.all(color: textColor, width: 0.5),
|
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: [
|
extensions: [
|
||||||
UserPillExtension(context, room),
|
UserPillExtension(context, room),
|
||||||
@ -114,6 +121,9 @@ class HtmlMessage extends StatelessWidget {
|
|||||||
style: TextStyle(fontSize: fontSize, color: textColor),
|
style: TextStyle(fontSize: fontSize, color: textColor),
|
||||||
),
|
),
|
||||||
const TableHtmlExtension(),
|
const TableHtmlExtension(),
|
||||||
|
SpoilerExtension(textColor: textColor),
|
||||||
|
const ImageExtension(),
|
||||||
|
FontColorExtension(),
|
||||||
],
|
],
|
||||||
onLinkTap: (url, _, __) => UrlLauncher(context, url).launchUrl(),
|
onLinkTap: (url, _, __) => UrlLauncher(context, url).launchUrl(),
|
||||||
onlyRenderTheseTags: const {
|
onlyRenderTheseTags: const {
|
||||||
@ -163,13 +173,135 @@ class HtmlMessage extends StatelessWidget {
|
|||||||
'caption',
|
'caption',
|
||||||
'pre',
|
'pre',
|
||||||
'span',
|
'span',
|
||||||
// TODO: Implement image extension for Mxc URIs
|
'img',
|
||||||
//'img',
|
|
||||||
'details',
|
'details',
|
||||||
'summary'
|
'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 {
|
class MatrixMathExtension extends HtmlExtension {
|
||||||
final TextStyle? style;
|
final TextStyle? style;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user