diff --git a/lib/components/html_message.dart b/lib/components/html_message.dart
new file mode 100644
index 0000000..a0b3092
--- /dev/null
+++ b/lib/components/html_message.dart
@@ -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,
+ );
+ },
+ );
+ }
+}
diff --git a/lib/components/matrix.dart b/lib/components/matrix.dart
index 4c3c49d..e032daa 100644
--- a/lib/components/matrix.dart
+++ b/lib/components/matrix.dart
@@ -55,6 +55,7 @@ class MatrixState extends State {
String activeRoomId;
File wallpaper;
+ bool renderHtml = false;
String jitsiInstance = 'https://meet.jit.si/';
@@ -189,6 +190,9 @@ class MatrixState extends State {
wallpaper = file;
}
});
+ client.storeAPI.getItem("chat.fluffy.renderHtml").then((final render) async {
+ renderHtml = render == "1";
+ });
}
super.initState();
}
diff --git a/lib/components/message_content.dart b/lib/components/message_content.dart
index 12319a1..cf60e73 100644
--- a/lib/components/message_content.dart
+++ b/lib/components/message_content.dart
@@ -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
}
}
diff --git a/lib/components/reply_content.dart b/lib/components/reply_content.dart
index ed39323..1cc56aa 100644
--- a/lib/components/reply_content.dart
+++ b/lib/components/reply_content.dart
@@ -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: [
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,
],
),
),
diff --git a/lib/l10n/intl_de.arb b/lib/l10n/intl_de.arb
index 310f80f..91aa4b8 100644
--- a/lib/l10n/intl_de.arb
+++ b/lib/l10n/intl_de.arb
@@ -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": {}
}
-}
\ No newline at end of file
+}
diff --git a/lib/l10n/intl_messages.arb b/lib/l10n/intl_messages.arb
index d696772..f924921 100644
--- a/lib/l10n/intl_messages.arb
+++ b/lib/l10n/intl_messages.arb
@@ -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": {}
}
-}
\ No newline at end of file
+}
diff --git a/lib/l10n/l10n.dart b/lib/l10n/l10n.dart
index a64f0ce..172de07 100644
--- a/lib/l10n/l10n.dart
+++ b/lib/l10n/l10n.dart
@@ -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(
diff --git a/lib/l10n/messages_de.dart b/lib/l10n/messages_de.dart
index 952c2ed..7d38c7f 100644
--- a/lib/l10n/messages_de.dart
+++ b/lib/l10n/messages_de.dart
@@ -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"),
diff --git a/lib/l10n/messages_messages.dart b/lib/l10n/messages_messages.dart
index 15cf8f4..18c5b56 100644
--- a/lib/l10n/messages_messages.dart
+++ b/lib/l10n/messages_messages.dart
@@ -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"),
diff --git a/lib/views/settings.dart b/lib/views/settings.dart
index 9956984..69305d5 100644
--- a/lib/views/settings.dart
+++ b/lib/views/settings.dart
@@ -210,6 +210,28 @@ class _SettingsState extends State {
);
}),
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,
diff --git a/pubspec.lock b/pubspec.lock
index 77f6bd0..e2de28e 100644
--- a/pubspec.lock
+++ b/pubspec.lock
@@ -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:
diff --git a/pubspec.yaml b/pubspec.yaml
index 9d83647..395866e 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -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