mirror of
https://gitlab.com/famedly/fluffychat.git
synced 2024-12-18 02:42:34 +01:00
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;
|
String activeRoomId;
|
||||||
File wallpaper;
|
File wallpaper;
|
||||||
|
bool renderHtml = false;
|
||||||
|
|
||||||
String jitsiInstance = 'https://meet.jit.si/';
|
String jitsiInstance = 'https://meet.jit.si/';
|
||||||
|
|
||||||
@ -189,6 +190,9 @@ class MatrixState extends State<Matrix> {
|
|||||||
wallpaper = file;
|
wallpaper = file;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
client.storeAPI.getItem("chat.fluffy.renderHtml").then((final render) async {
|
||||||
|
renderHtml = render == "1";
|
||||||
|
});
|
||||||
}
|
}
|
||||||
super.initState();
|
super.initState();
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,7 @@ import 'package:link_text/link_text.dart';
|
|||||||
import 'package:url_launcher/url_launcher.dart';
|
import 'package:url_launcher/url_launcher.dart';
|
||||||
import 'matrix.dart';
|
import 'matrix.dart';
|
||||||
import 'message_download_content.dart';
|
import 'message_download_content.dart';
|
||||||
|
import 'html_message.dart';
|
||||||
|
|
||||||
class MessageContent extends StatelessWidget {
|
class MessageContent extends StatelessWidget {
|
||||||
final Event event;
|
final Event event;
|
||||||
@ -36,13 +37,30 @@ class MessageContent extends StatelessWidget {
|
|||||||
case MessageTypes.Video:
|
case MessageTypes.Video:
|
||||||
case MessageTypes.File:
|
case MessageTypes.File:
|
||||||
return MessageDownloadContent(event, textColor);
|
return MessageDownloadContent(event, textColor);
|
||||||
case MessageTypes.BadEncrypted:
|
|
||||||
case MessageTypes.Text:
|
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.Reply:
|
||||||
case MessageTypes.Location:
|
case MessageTypes.Location:
|
||||||
case MessageTypes.None:
|
case MessageTypes.None:
|
||||||
case MessageTypes.Notice:
|
textmessage:
|
||||||
case MessageTypes.Emote:
|
|
||||||
default:
|
default:
|
||||||
if (event.content['msgtype'] == Matrix.callNamespace) {
|
if (event.content['msgtype'] == Matrix.callNamespace) {
|
||||||
return RaisedButton(
|
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:fluffychat/l10n/l10n.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
import 'html_message.dart';
|
||||||
|
import 'matrix.dart';
|
||||||
|
|
||||||
class ReplyContent extends StatelessWidget {
|
class ReplyContent extends StatelessWidget {
|
||||||
final Event replyEvent;
|
final Event replyEvent;
|
||||||
final bool lightText;
|
final bool lightText;
|
||||||
@ -11,6 +14,40 @@ class ReplyContent extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
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(
|
return Row(
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
Container(
|
Container(
|
||||||
@ -34,20 +71,7 @@ class ReplyContent extends StatelessWidget {
|
|||||||
lightText ? Colors.white : Theme.of(context).primaryColor,
|
lightText ? Colors.white : Theme.of(context).primaryColor,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Text(
|
replyBody,
|
||||||
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),
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -248,6 +248,11 @@
|
|||||||
"type": "text",
|
"type": "text",
|
||||||
"placeholders": {}
|
"placeholders": {}
|
||||||
},
|
},
|
||||||
|
"Chat": "Chat",
|
||||||
|
"@Chat": {
|
||||||
|
"type": "text",
|
||||||
|
"placeholders": {}
|
||||||
|
},
|
||||||
"Chat details": "Gruppeninfo",
|
"Chat details": "Gruppeninfo",
|
||||||
"@Chat details": {
|
"@Chat details": {
|
||||||
"type": "text",
|
"type": "text",
|
||||||
@ -847,6 +852,11 @@
|
|||||||
"type": "text",
|
"type": "text",
|
||||||
"placeholders": {}
|
"placeholders": {}
|
||||||
},
|
},
|
||||||
|
"Render rich message content": "Zeige Nachrichtenformatierungen an",
|
||||||
|
"@Render rich message content": {
|
||||||
|
"type": "text",
|
||||||
|
"placeholders": {}
|
||||||
|
},
|
||||||
"redactedAnEvent": "{username} hat ein Event enternt",
|
"redactedAnEvent": "{username} hat ein Event enternt",
|
||||||
"@redactedAnEvent": {
|
"@redactedAnEvent": {
|
||||||
"type": "text",
|
"type": "text",
|
||||||
@ -1317,4 +1327,4 @@
|
|||||||
"type": "text",
|
"type": "text",
|
||||||
"placeholders": {}
|
"placeholders": {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"@@last_modified": "2020-05-09T12:56:54.540935",
|
"@@last_modified": "2020-05-09T13:02:58.452942",
|
||||||
"About": "About",
|
"About": "About",
|
||||||
"@About": {
|
"@About": {
|
||||||
"type": "text",
|
"type": "text",
|
||||||
@ -248,6 +248,11 @@
|
|||||||
"type": "text",
|
"type": "text",
|
||||||
"placeholders": {}
|
"placeholders": {}
|
||||||
},
|
},
|
||||||
|
"Chat": "Chat",
|
||||||
|
"@Chat": {
|
||||||
|
"type": "text",
|
||||||
|
"placeholders": {}
|
||||||
|
},
|
||||||
"Chat details": "Chat details",
|
"Chat details": "Chat details",
|
||||||
"@Chat details": {
|
"@Chat details": {
|
||||||
"type": "text",
|
"type": "text",
|
||||||
@ -852,6 +857,11 @@
|
|||||||
"type": "text",
|
"type": "text",
|
||||||
"placeholders": {}
|
"placeholders": {}
|
||||||
},
|
},
|
||||||
|
"Render rich message content": "Render rich message content",
|
||||||
|
"@Render rich message content": {
|
||||||
|
"type": "text",
|
||||||
|
"placeholders": {}
|
||||||
|
},
|
||||||
"Recording": "Recording",
|
"Recording": "Recording",
|
||||||
"@Recording": {
|
"@Recording": {
|
||||||
"type": "text",
|
"type": "text",
|
||||||
@ -1327,4 +1337,4 @@
|
|||||||
"type": "text",
|
"type": "text",
|
||||||
"placeholders": {}
|
"placeholders": {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -206,6 +206,8 @@ class L10n extends MatrixLocalizations {
|
|||||||
String get channelCorruptedDecryptError =>
|
String get channelCorruptedDecryptError =>
|
||||||
Intl.message("The encryption has been corrupted");
|
Intl.message("The encryption has been corrupted");
|
||||||
|
|
||||||
|
String get chat => Intl.message('Chat');
|
||||||
|
|
||||||
String get chatDetails => Intl.message('Chat details');
|
String get chatDetails => Intl.message('Chat details');
|
||||||
|
|
||||||
String get chooseAStrongPassword => Intl.message("Choose a strong password");
|
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 rejoin => Intl.message("Rejoin");
|
||||||
|
|
||||||
|
String get renderRichContent => Intl.message("Render rich message content");
|
||||||
|
|
||||||
String get recording => Intl.message("Recording");
|
String get recording => Intl.message("Recording");
|
||||||
|
|
||||||
String redactedAnEvent(String username) => Intl.message(
|
String redactedAnEvent(String username) => Intl.message(
|
||||||
|
@ -164,6 +164,7 @@ class MessageLookup extends MessageLookupByLibrary {
|
|||||||
"Change wallpaper" : MessageLookupByLibrary.simpleMessage("Hintergrund ändern"),
|
"Change wallpaper" : MessageLookupByLibrary.simpleMessage("Hintergrund ändern"),
|
||||||
"Change your style" : MessageLookupByLibrary.simpleMessage("Ändere Deinen Style"),
|
"Change your style" : MessageLookupByLibrary.simpleMessage("Ändere Deinen Style"),
|
||||||
"Changelog" : MessageLookupByLibrary.simpleMessage("Changelog"),
|
"Changelog" : MessageLookupByLibrary.simpleMessage("Changelog"),
|
||||||
|
"Chat" : MessageLookupByLibrary.simpleMessage("Chat"),
|
||||||
"Chat details" : MessageLookupByLibrary.simpleMessage("Gruppeninfo"),
|
"Chat details" : MessageLookupByLibrary.simpleMessage("Gruppeninfo"),
|
||||||
"Choose a strong password" : MessageLookupByLibrary.simpleMessage("Wähle ein sicheres Passwort"),
|
"Choose a strong password" : MessageLookupByLibrary.simpleMessage("Wähle ein sicheres Passwort"),
|
||||||
"Choose a username" : MessageLookupByLibrary.simpleMessage("Wähle einen Benutzernamen"),
|
"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 device" : MessageLookupByLibrary.simpleMessage("Gerät entfernen"),
|
||||||
"Remove exile" : MessageLookupByLibrary.simpleMessage("Verbannung aufheben"),
|
"Remove exile" : MessageLookupByLibrary.simpleMessage("Verbannung aufheben"),
|
||||||
"Remove message" : MessageLookupByLibrary.simpleMessage("Nachricht entfernen"),
|
"Remove message" : MessageLookupByLibrary.simpleMessage("Nachricht entfernen"),
|
||||||
|
"Render rich message content" : MessageLookupByLibrary.simpleMessage("Zeige Nachrichtenformatierungen an"),
|
||||||
"Reply" : MessageLookupByLibrary.simpleMessage("Antworten"),
|
"Reply" : MessageLookupByLibrary.simpleMessage("Antworten"),
|
||||||
"Request permission" : MessageLookupByLibrary.simpleMessage("Berechtigung anfragen"),
|
"Request permission" : MessageLookupByLibrary.simpleMessage("Berechtigung anfragen"),
|
||||||
"Request to read older messages" : MessageLookupByLibrary.simpleMessage("Anfrage um ältere Nachrichten zu lesen"),
|
"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 wallpaper" : MessageLookupByLibrary.simpleMessage("Change wallpaper"),
|
||||||
"Change your style" : MessageLookupByLibrary.simpleMessage("Change your style"),
|
"Change your style" : MessageLookupByLibrary.simpleMessage("Change your style"),
|
||||||
"Changelog" : MessageLookupByLibrary.simpleMessage("Changelog"),
|
"Changelog" : MessageLookupByLibrary.simpleMessage("Changelog"),
|
||||||
|
"Chat" : MessageLookupByLibrary.simpleMessage("Chat"),
|
||||||
"Chat details" : MessageLookupByLibrary.simpleMessage("Chat details"),
|
"Chat details" : MessageLookupByLibrary.simpleMessage("Chat details"),
|
||||||
"Choose a strong password" : MessageLookupByLibrary.simpleMessage("Choose a strong password"),
|
"Choose a strong password" : MessageLookupByLibrary.simpleMessage("Choose a strong password"),
|
||||||
"Choose a username" : MessageLookupByLibrary.simpleMessage("Choose a username"),
|
"Choose a username" : MessageLookupByLibrary.simpleMessage("Choose a username"),
|
||||||
@ -263,6 +264,7 @@ class MessageLookup extends MessageLookupByLibrary {
|
|||||||
"Remove device" : MessageLookupByLibrary.simpleMessage("Remove device"),
|
"Remove device" : MessageLookupByLibrary.simpleMessage("Remove device"),
|
||||||
"Remove exile" : MessageLookupByLibrary.simpleMessage("Remove exile"),
|
"Remove exile" : MessageLookupByLibrary.simpleMessage("Remove exile"),
|
||||||
"Remove message" : MessageLookupByLibrary.simpleMessage("Remove message"),
|
"Remove message" : MessageLookupByLibrary.simpleMessage("Remove message"),
|
||||||
|
"Render rich message content" : MessageLookupByLibrary.simpleMessage("Render rich message content"),
|
||||||
"Reply" : MessageLookupByLibrary.simpleMessage("Reply"),
|
"Reply" : MessageLookupByLibrary.simpleMessage("Reply"),
|
||||||
"Request permission" : MessageLookupByLibrary.simpleMessage("Request permission"),
|
"Request permission" : MessageLookupByLibrary.simpleMessage("Request permission"),
|
||||||
"Request to read older messages" : MessageLookupByLibrary.simpleMessage("Request to read older messages"),
|
"Request to read older messages" : MessageLookupByLibrary.simpleMessage("Request to read older messages"),
|
||||||
|
@ -210,6 +210,28 @@ class _SettingsState extends State<Settings> {
|
|||||||
);
|
);
|
||||||
}),
|
}),
|
||||||
Divider(thickness: 1),
|
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(
|
ListTile(
|
||||||
title: Text(
|
title: Text(
|
||||||
L10n.of(context).account,
|
L10n.of(context).account,
|
||||||
|
@ -181,6 +181,13 @@ packages:
|
|||||||
description: flutter
|
description: flutter
|
||||||
source: sdk
|
source: sdk
|
||||||
version: "0.0.0"
|
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:
|
flutter_secure_storage:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@ -738,7 +745,7 @@ packages:
|
|||||||
name: webkit_inspection_protocol
|
name: webkit_inspection_protocol
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.5.2"
|
version: "0.5.3"
|
||||||
webview_flutter:
|
webview_flutter:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
@ -54,6 +54,7 @@ dependencies:
|
|||||||
open_file: ^3.0.1
|
open_file: ^3.0.1
|
||||||
mime_type: ^0.3.0
|
mime_type: ^0.3.0
|
||||||
flutter_styled_toast: ^1.2.1
|
flutter_styled_toast: ^1.2.1
|
||||||
|
flutter_matrix_html: ^0.0.5
|
||||||
|
|
||||||
intl: ^0.16.0
|
intl: ^0.16.0
|
||||||
intl_translation: ^0.17.9
|
intl_translation: ^0.17.9
|
||||||
|
Loading…
Reference in New Issue
Block a user