fix html rendering for image bodies

This commit is contained in:
Henry Hiles 2026-03-12 20:18:03 -04:00
commit cb22bdc314
No known key found for this signature in database

View file

@ -51,6 +51,37 @@ class RoomChat extends HookConsumerWidget {
final theme = Theme.of(context); final theme = Theme.of(context);
final danger = theme.colorScheme.error; final danger = theme.colorScheme.error;
Widget getTextWidget(TextMessage message) => Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Html(
textStyle: message.metadata?["big"] == true
? TextStyle(fontSize: 32)
: null,
message.text
.replaceAllMapped(
RegExp(
"(<a\\b[^>]*>.*?<\\/a>)|(\\bhttps?:\\/\\/[^\\s<]+)",
caseSensitive: false,
),
(m) {
// If it's already an <a> tag, leave it unchanged
if (m.group(1) != null) {
return m.group(1)!;
}
// Otherwise, wrap the bare URL
final url = m.group(2)!;
return "<a href=\"$url\">$url</a>";
},
)
.replaceAll("\n", "<br class=\"fake-break\"/>"),
),
if (message.editedAt != null)
Text("(edited)", style: theme.textTheme.labelSmall),
],
);
if (room == null || userId == null || room.metadata?.id == null) { if (room == null || userId == null || room.metadata?.id == null) {
return Center( return Center(
child: Text( child: Text(
@ -401,44 +432,7 @@ class RoomChat extends HookConsumerWidget {
required bool isSentByMe, required bool isSentByMe,
MessageGroupStatus? groupStatus, MessageGroupStatus? groupStatus,
}) => FlyerChatTextMessage( }) => FlyerChatTextMessage(
customWidget: Column( customWidget: getTextWidget(message),
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Html(
textStyle:
message.metadata?["big"] == true
? TextStyle(fontSize: 32)
: null,
message.text
.replaceAllMapped(
RegExp(
"(<a\\b[^>]*>.*?<\\/a>)|(\\bhttps?:\\/\\/[^\\s<]+)",
caseSensitive: false,
),
(m) {
// If it's already an <a> tag, leave it unchanged
if (m.group(1) != null) {
return m.group(1)!;
}
// Otherwise, wrap the bare URL
final url = m.group(2)!;
return "<a href=\"$url\">$url</a>";
},
)
.replaceAll(
"\n",
"<br class=\"fake-break\"/>",
),
),
if (message.editedAt != null)
Text(
"(edited)",
style: theme.textTheme.labelSmall,
),
],
),
topWidget: TopWidget( topWidget: TopWidget(
message, message,
groupStatus: groupStatus, groupStatus: groupStatus,
@ -473,60 +467,69 @@ class RoomChat extends HookConsumerWidget {
index, { index, {
required bool isSentByMe, required bool isSentByMe,
MessageGroupStatus? groupStatus, MessageGroupStatus? groupStatus,
}) => Column( }) {
spacing: 4, final textMessage =
crossAxisAlignment: isSentByMe message.text?.isNotEmpty == true
? CrossAxisAlignment.end ? TextMessage(
: CrossAxisAlignment.start,
children: [
SizedBox(height: 12),
if (message.text?.isNotEmpty == true)
FlyerChatTextMessage(
topWidget: TopWidget(
message,
groupStatus: groupStatus,
alwaysShow: true,
),
message: TextMessage(
id: "${message.id}-text", id: "${message.id}-text",
authorId: message.authorId, authorId: message.authorId,
text: message.text!, text: message.text!,
)
: null;
return Column(
spacing: 4,
crossAxisAlignment: isSentByMe
? CrossAxisAlignment.end
: CrossAxisAlignment.start,
children: [
SizedBox(height: 12),
if (textMessage != null)
FlyerChatTextMessage(
customWidget: getTextWidget(
textMessage,
),
topWidget: TopWidget(
message,
groupStatus: groupStatus,
alwaysShow: true,
),
message: textMessage,
index: index,
), ),
index: index, FlyerChatImageMessage(
), topWidget:
FlyerChatImageMessage( message.text?.isNotEmpty == true
topWidget: ? null
message.text?.isNotEmpty == true : TopWidget(
? null message,
: TopWidget( groupStatus: groupStatus,
message, alwaysShow: true,
groupStatus: groupStatus, ),
alwaysShow: true, customImageProvider: CachedNetworkImage(
), message.source,
customImageProvider: CachedNetworkImage( ref.watch(
message.source, CrossCacheController.provider,
ref.watch( ),
CrossCacheController.provider, headers: ref.headers,
), ),
headers: ref.headers, errorBuilder:
), (context, error, stackTrace) =>
errorBuilder: Center(
(context, error, stackTrace) => child: Text(
Center( "Image Failed to Load",
child: Text( style: TextStyle(
"Image Failed to Load", color: Theme.of(
style: TextStyle( context,
color: Theme.of( ).colorScheme.error,
context, ),
).colorScheme.error,
), ),
), ),
), message: message,
message: message, index: index,
index: index, ),
), ],
], );
), },
fileMessageBuilder: fileMessageBuilder:
( (
_, _,