Add HTML render
This commit is contained in:
parent
eb72198048
commit
3ee1018eb5
41
lib/components/html_message.dart
Normal file
41
lib/components/html_message.dart
Normal file
|
@ -0,0 +1,41 @@
|
|||
import 'package:famedlysdk/famedlysdk.dart';
|
||||
import 'package:flutter_matrix_html/flutter_html.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
|
||||
import 'matrix.dart';
|
||||
|
||||
class HtmlMessage extends StatelessWidget {
|
||||
final String html;
|
||||
final Color textColor;
|
||||
final int maxLines;
|
||||
|
||||
const HtmlMessage({this.html, this.textColor, this.maxLines});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
// there is no need to pre-validate the html, as we validate it while rendering
|
||||
|
||||
return Html(
|
||||
data: html,
|
||||
defaultTextStyle: TextStyle(color: textColor),
|
||||
shrinkToFit: true,
|
||||
maxLines: maxLines,
|
||||
onLinkTap: (String url) {
|
||||
if (url == null || url.isEmpty) {
|
||||
return;
|
||||
}
|
||||
launch(url);
|
||||
},
|
||||
getMxcUrl: (String mxc, double width, double height) {
|
||||
final ratio = MediaQuery.of(context).devicePixelRatio;
|
||||
return Uri.parse(mxc)?.getThumbnail(
|
||||
Matrix.of(context).client,
|
||||
width: (width ?? 800) * ratio,
|
||||
height: (height ?? 800) * ratio,
|
||||
method: ThumbnailMethod.scale,
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
|
@ -55,6 +55,7 @@ class MatrixState extends State<Matrix> {
|
|||
|
||||
String activeRoomId;
|
||||
File wallpaper;
|
||||
bool renderHtml = false;
|
||||
|
||||
String jitsiInstance = 'https://meet.jit.si/';
|
||||
|
||||
|
@ -189,6 +190,9 @@ class MatrixState extends State<Matrix> {
|
|||
wallpaper = file;
|
||||
}
|
||||
});
|
||||
client.storeAPI.getItem("chat.fluffy.renderHtml").then((final render) async {
|
||||
renderHtml = render == "1";
|
||||
});
|
||||
}
|
||||
super.initState();
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ import 'package:link_text/link_text.dart';
|
|||
import 'package:url_launcher/url_launcher.dart';
|
||||
import 'matrix.dart';
|
||||
import 'message_download_content.dart';
|
||||
import 'html_message.dart';
|
||||
|
||||
class MessageContent extends StatelessWidget {
|
||||
final Event event;
|
||||
|
@ -36,13 +37,30 @@ class MessageContent extends StatelessWidget {
|
|||
case MessageTypes.Video:
|
||||
case MessageTypes.File:
|
||||
return MessageDownloadContent(event, textColor);
|
||||
case MessageTypes.BadEncrypted:
|
||||
case MessageTypes.Text:
|
||||
case MessageTypes.Notice:
|
||||
case MessageTypes.Emote:
|
||||
if (
|
||||
Matrix.of(context).renderHtml && !event.redacted &&
|
||||
event.content['format'] == 'org.matrix.custom.html' &&
|
||||
event.content['formatted_body'] is String
|
||||
) {
|
||||
String html = event.content['formatted_body'];
|
||||
if (event.messageType == MessageTypes.Emote) {
|
||||
html = "* $html";
|
||||
}
|
||||
return HtmlMessage(
|
||||
html: html,
|
||||
textColor: textColor,
|
||||
);
|
||||
}
|
||||
// else we fall through to the normal message rendering
|
||||
continue textmessage;
|
||||
case MessageTypes.BadEncrypted:
|
||||
case MessageTypes.Reply:
|
||||
case MessageTypes.Location:
|
||||
case MessageTypes.None:
|
||||
case MessageTypes.Notice:
|
||||
case MessageTypes.Emote:
|
||||
textmessage:
|
||||
default:
|
||||
if (event.content['msgtype'] == Matrix.callNamespace) {
|
||||
return RaisedButton(
|
||||
|
@ -76,5 +94,6 @@ class MessageContent extends StatelessWidget {
|
|||
),
|
||||
);
|
||||
}
|
||||
return Container(); // else flutter analyze complains
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,9 @@ import 'package:famedlysdk/famedlysdk.dart';
|
|||
import 'package:fluffychat/l10n/l10n.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'html_message.dart';
|
||||
import 'matrix.dart';
|
||||
|
||||
class ReplyContent extends StatelessWidget {
|
||||
final Event replyEvent;
|
||||
final bool lightText;
|
||||
|
@ -11,6 +14,40 @@ class ReplyContent extends StatelessWidget {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
Widget replyBody;
|
||||
if (
|
||||
replyEvent != null && Matrix.of(context).renderHtml &&
|
||||
[EventTypes.Message, EventTypes.Encrypted].contains(replyEvent.type) &&
|
||||
[MessageTypes.Text, MessageTypes.Notice, MessageTypes.Emote].contains(replyEvent.messageType) &&
|
||||
!replyEvent.redacted && replyEvent.content['format'] == 'org.matrix.custom.html' && replyEvent.content['formatted_body'] is String
|
||||
) {
|
||||
String html = replyEvent.content['formatted_body'];
|
||||
if (replyEvent.messageType == MessageTypes.Emote) {
|
||||
html = "* $html";
|
||||
}
|
||||
replyBody = HtmlMessage(
|
||||
html: html,
|
||||
textColor: lightText
|
||||
? Colors.white
|
||||
: Theme.of(context).textTheme.bodyText2.color,
|
||||
maxLines: 1,
|
||||
);
|
||||
} else {
|
||||
replyBody = Text(
|
||||
replyEvent?.getLocalizedBody(
|
||||
L10n.of(context),
|
||||
withSenderNamePrefix: false,
|
||||
hideReply: true,
|
||||
) ??
|
||||
"",
|
||||
overflow: TextOverflow.ellipsis,
|
||||
maxLines: 1,
|
||||
style: TextStyle(
|
||||
color: lightText
|
||||
? Colors.white
|
||||
: Theme.of(context).textTheme.bodyText2.color),
|
||||
);
|
||||
}
|
||||
return Row(
|
||||
children: <Widget>[
|
||||
Container(
|
||||
|
@ -34,20 +71,7 @@ class ReplyContent extends StatelessWidget {
|
|||
lightText ? Colors.white : Theme.of(context).primaryColor,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
replyEvent?.getLocalizedBody(
|
||||
L10n.of(context),
|
||||
withSenderNamePrefix: false,
|
||||
hideReply: true,
|
||||
) ??
|
||||
"",
|
||||
overflow: TextOverflow.ellipsis,
|
||||
maxLines: 1,
|
||||
style: TextStyle(
|
||||
color: lightText
|
||||
? Colors.white
|
||||
: Theme.of(context).textTheme.bodyText2.color),
|
||||
),
|
||||
replyBody,
|
||||
],
|
||||
),
|
||||
),
|
||||
|
|
|
@ -248,6 +248,11 @@
|
|||
"type": "text",
|
||||
"placeholders": {}
|
||||
},
|
||||
"Chat": "Chat",
|
||||
"@Chat": {
|
||||
"type": "text",
|
||||
"placeholders": {}
|
||||
},
|
||||
"Chat details": "Gruppeninfo",
|
||||
"@Chat details": {
|
||||
"type": "text",
|
||||
|
@ -847,6 +852,11 @@
|
|||
"type": "text",
|
||||
"placeholders": {}
|
||||
},
|
||||
"Render rich message content": "Zeige Nachrichtenformatierungen an",
|
||||
"@Render rich message content": {
|
||||
"type": "text",
|
||||
"placeholders": {}
|
||||
},
|
||||
"redactedAnEvent": "{username} hat ein Event enternt",
|
||||
"@redactedAnEvent": {
|
||||
"type": "text",
|
||||
|
@ -1317,4 +1327,4 @@
|
|||
"type": "text",
|
||||
"placeholders": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"@@last_modified": "2020-05-09T12:56:54.540935",
|
||||
"@@last_modified": "2020-05-09T13:02:58.452942",
|
||||
"About": "About",
|
||||
"@About": {
|
||||
"type": "text",
|
||||
|
@ -248,6 +248,11 @@
|
|||
"type": "text",
|
||||
"placeholders": {}
|
||||
},
|
||||
"Chat": "Chat",
|
||||
"@Chat": {
|
||||
"type": "text",
|
||||
"placeholders": {}
|
||||
},
|
||||
"Chat details": "Chat details",
|
||||
"@Chat details": {
|
||||
"type": "text",
|
||||
|
@ -852,6 +857,11 @@
|
|||
"type": "text",
|
||||
"placeholders": {}
|
||||
},
|
||||
"Render rich message content": "Render rich message content",
|
||||
"@Render rich message content": {
|
||||
"type": "text",
|
||||
"placeholders": {}
|
||||
},
|
||||
"Recording": "Recording",
|
||||
"@Recording": {
|
||||
"type": "text",
|
||||
|
@ -1327,4 +1337,4 @@
|
|||
"type": "text",
|
||||
"placeholders": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -206,6 +206,8 @@ class L10n extends MatrixLocalizations {
|
|||
String get channelCorruptedDecryptError =>
|
||||
Intl.message("The encryption has been corrupted");
|
||||
|
||||
String get chat => Intl.message('Chat');
|
||||
|
||||
String get chatDetails => Intl.message('Chat details');
|
||||
|
||||
String get chooseAStrongPassword => Intl.message("Choose a strong password");
|
||||
|
@ -524,6 +526,8 @@ class L10n extends MatrixLocalizations {
|
|||
|
||||
String get rejoin => Intl.message("Rejoin");
|
||||
|
||||
String get renderRichContent => Intl.message("Render rich message content");
|
||||
|
||||
String get recording => Intl.message("Recording");
|
||||
|
||||
String redactedAnEvent(String username) => Intl.message(
|
||||
|
|
|
@ -164,6 +164,7 @@ class MessageLookup extends MessageLookupByLibrary {
|
|||
"Change wallpaper" : MessageLookupByLibrary.simpleMessage("Hintergrund ändern"),
|
||||
"Change your style" : MessageLookupByLibrary.simpleMessage("Ändere Deinen Style"),
|
||||
"Changelog" : MessageLookupByLibrary.simpleMessage("Changelog"),
|
||||
"Chat" : MessageLookupByLibrary.simpleMessage("Chat"),
|
||||
"Chat details" : MessageLookupByLibrary.simpleMessage("Gruppeninfo"),
|
||||
"Choose a strong password" : MessageLookupByLibrary.simpleMessage("Wähle ein sicheres Passwort"),
|
||||
"Choose a username" : MessageLookupByLibrary.simpleMessage("Wähle einen Benutzernamen"),
|
||||
|
@ -261,6 +262,7 @@ class MessageLookup extends MessageLookupByLibrary {
|
|||
"Remove device" : MessageLookupByLibrary.simpleMessage("Gerät entfernen"),
|
||||
"Remove exile" : MessageLookupByLibrary.simpleMessage("Verbannung aufheben"),
|
||||
"Remove message" : MessageLookupByLibrary.simpleMessage("Nachricht entfernen"),
|
||||
"Render rich message content" : MessageLookupByLibrary.simpleMessage("Zeige Nachrichtenformatierungen an"),
|
||||
"Reply" : MessageLookupByLibrary.simpleMessage("Antworten"),
|
||||
"Request permission" : MessageLookupByLibrary.simpleMessage("Berechtigung anfragen"),
|
||||
"Request to read older messages" : MessageLookupByLibrary.simpleMessage("Anfrage um ältere Nachrichten zu lesen"),
|
||||
|
|
|
@ -164,6 +164,7 @@ class MessageLookup extends MessageLookupByLibrary {
|
|||
"Change wallpaper" : MessageLookupByLibrary.simpleMessage("Change wallpaper"),
|
||||
"Change your style" : MessageLookupByLibrary.simpleMessage("Change your style"),
|
||||
"Changelog" : MessageLookupByLibrary.simpleMessage("Changelog"),
|
||||
"Chat" : MessageLookupByLibrary.simpleMessage("Chat"),
|
||||
"Chat details" : MessageLookupByLibrary.simpleMessage("Chat details"),
|
||||
"Choose a strong password" : MessageLookupByLibrary.simpleMessage("Choose a strong password"),
|
||||
"Choose a username" : MessageLookupByLibrary.simpleMessage("Choose a username"),
|
||||
|
@ -263,6 +264,7 @@ class MessageLookup extends MessageLookupByLibrary {
|
|||
"Remove device" : MessageLookupByLibrary.simpleMessage("Remove device"),
|
||||
"Remove exile" : MessageLookupByLibrary.simpleMessage("Remove exile"),
|
||||
"Remove message" : MessageLookupByLibrary.simpleMessage("Remove message"),
|
||||
"Render rich message content" : MessageLookupByLibrary.simpleMessage("Render rich message content"),
|
||||
"Reply" : MessageLookupByLibrary.simpleMessage("Reply"),
|
||||
"Request permission" : MessageLookupByLibrary.simpleMessage("Request permission"),
|
||||
"Request to read older messages" : MessageLookupByLibrary.simpleMessage("Request to read older messages"),
|
||||
|
|
|
@ -210,6 +210,28 @@ class _SettingsState extends State<Settings> {
|
|||
);
|
||||
}),
|
||||
Divider(thickness: 1),
|
||||
ListTile(
|
||||
title: Text(
|
||||
L10n.of(context).chat,
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).primaryColor,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
),
|
||||
ListTile(
|
||||
title: Text(L10n.of(context).renderRichContent),
|
||||
trailing: Switch(
|
||||
value: Matrix.of(context).renderHtml,
|
||||
activeColor: Theme.of(context).primaryColor,
|
||||
onChanged: (bool newValue) async {
|
||||
Matrix.of(context).renderHtml = newValue;
|
||||
await client.storeAPI.setItem("chat.fluffy.renderHtml", newValue ? "1" : "0");
|
||||
setState(() => null);
|
||||
},
|
||||
),
|
||||
),
|
||||
Divider(thickness: 1),
|
||||
ListTile(
|
||||
title: Text(
|
||||
L10n.of(context).account,
|
||||
|
|
|
@ -181,6 +181,13 @@ packages:
|
|||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.0"
|
||||
flutter_matrix_html:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: flutter_matrix_html
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.0.5"
|
||||
flutter_secure_storage:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@ -738,7 +745,7 @@ packages:
|
|||
name: webkit_inspection_protocol
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.5.2"
|
||||
version: "0.5.3"
|
||||
webview_flutter:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
|
|
@ -54,6 +54,7 @@ dependencies:
|
|||
open_file: ^3.0.1
|
||||
mime_type: ^0.3.0
|
||||
flutter_styled_toast: ^1.2.1
|
||||
flutter_matrix_html: ^0.0.5
|
||||
|
||||
intl: ^0.16.0
|
||||
intl_translation: ^0.17.9
|
||||
|
|
Loading…
Reference in a new issue