aboutsummaryrefslogtreecommitdiff
path: root/src/plugins
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins')
-rw-r--r--src/plugins/Matrix.cpp134
1 files changed, 124 insertions, 10 deletions
diff --git a/src/plugins/Matrix.cpp b/src/plugins/Matrix.cpp
index 0fcc1c3..e4a7bd1 100644
--- a/src/plugins/Matrix.cpp
+++ b/src/plugins/Matrix.cpp
@@ -18,6 +18,7 @@
#include <unistd.h>
#include <malloc.h>
#include "../../include/QuickMedia.hpp"
+#include <HtmlParser.h>
// TODO: Use string assign with string length instead of assigning to c string (which calls strlen)
// Show images/videos inline.
@@ -598,15 +599,15 @@ namespace QuickMedia {
}
static std::string message_to_room_description_text(Message *message) {
- std::string body = strip(message->body);
+ std::string body = strip(formatted_text_to_qm_text(message->body.c_str(), message->body.size()));
if(message->type == MessageType::REACTION)
- return "Reacted with: " + extract_first_line_remove_newline_elipses(body, 150);
+ return "Reacted with: " + body;
else if(message->related_event_type == RelatedEventType::REPLY)
- return extract_first_line_remove_newline_elipses(remove_reply_formatting(body), 150);
+ return body;
else if(message->related_event_type == RelatedEventType::EDIT)
- return "Edited: " + extract_first_line_remove_newline_elipses(remove_reply_formatting(body), 150);
+ return "Edited: " + body;
else
- return extract_first_line_remove_newline_elipses(body, 150);
+ return body;
}
void MatrixQuickMedia::update_room_description(RoomData *room, const Messages &new_messages, bool is_initial_sync, bool sync_is_cache) {
@@ -672,13 +673,13 @@ namespace QuickMedia {
if(!room_desc.empty())
room_desc += '\n';
room_desc += "** " + std::to_string(unread_notification_count) + " unread mention(s) **"; // TODO: Better notification?
- room->body_item->set_description_color(get_theme().attention_alert_text_color);
+ room->body_item->set_description_color(get_theme().attention_alert_text_color, true);
} else {
room->body_item->set_description_color(get_theme().faded_text_color);
}
room->body_item->set_description(std::move(room_desc));
if(set_room_as_unread)
- room->body_item->set_title_color(get_theme().attention_alert_text_color);
+ room->body_item->set_title_color(get_theme().attention_alert_text_color, true);
room->last_message_read = false;
rooms_page->move_room_to_top(room);
@@ -1085,8 +1086,8 @@ namespace QuickMedia {
body_item->url = notification.event_id;
if(!notification.read) {
- body_item->set_author_color(get_theme().attention_alert_text_color);
- body_item->set_description_color(get_theme().attention_alert_text_color);
+ body_item->set_author_color(get_theme().attention_alert_text_color, true);
+ body_item->set_description_color(get_theme().attention_alert_text_color, true);
}
body_item->thumbnail_mask_type = ThumbnailMaskType::CIRCLE;
@@ -2232,6 +2233,115 @@ namespace QuickMedia {
return result;
}
+ // Returns -1 if its not a hex value
+ static int get_hex_value(char c) {
+ if(c >= '0' && c <= '9')
+ return c - '0';
+ else if(c >= 'a' && c <= 'f')
+ return 10 + (c - 'a');
+ else if(c >= 'A' && c <= 'F')
+ return 10 + (c - 'A');
+ else
+ return -1;
+ }
+
+ // Parses hex colors in the format #RRGGBB(AA)
+ static bool parse_hex_set_color(const char *str, int size, mgl::Color &color) {
+ if(size == 0)
+ return false;
+
+ // #RRGGBB(AA), case insensitive hex
+ if(str[0] != '#')
+ return false;
+
+ if(size - 1 != 6 && size - 1 != 8)
+ return false;
+
+ mgl::Color new_color;
+ for(int i = 1; i < size; i += 2) {
+ const int c1 = get_hex_value(str[i + 0]);
+ const int c2 = get_hex_value(str[i + 1]);
+ if(c1 == -1 || c2 == -1)
+ return false;
+ (&new_color.r)[(i - 1)/2] = (c1 << 4) | c2;
+ }
+ color = new_color;
+ return true;
+ }
+
+ struct FormattedTextParseUserdata {
+ std::string result;
+ int mx_reply_depth = 0;
+ bool inside_font_tag = false;
+ bool font_tag_has_custom_color = false;
+ bool inside_code_tag = false;
+ mgl::Color font_color = mgl::Color(255, 255, 255, 255);
+ };
+
+ // TODO: Full proper parsing with tag depth
+ static int formattext_text_parser_callback(HtmlParser *html_parser, HtmlParseType parse_type, void *userdata) {
+ FormattedTextParseUserdata &parse_userdata = *(FormattedTextParseUserdata*)userdata;
+ switch(parse_type) {
+ case HTML_PARSE_TAG_START: {
+ if(html_parser->tag_name.size == 2 && memcmp(html_parser->tag_name.data, "br", 2) == 0)
+ parse_userdata.result += '\n';
+ else if(html_parser->tag_name.size == 4 && memcmp(html_parser->tag_name.data, "font", 4) == 0)
+ parse_userdata.inside_font_tag = true;
+ else if(html_parser->tag_name.size == 8 && memcmp(html_parser->tag_name.data, "mx-reply", 8) == 0)
+ ++parse_userdata.mx_reply_depth;
+ else if(html_parser->tag_name.size == 4 && memcmp(html_parser->tag_name.data, "code", 4) == 0)
+ parse_userdata.inside_code_tag = true;
+ break;
+ }
+ case HTML_PARSE_TAG_END: {
+ /*if(html_parser->tag_name.size == 2 && memcmp(html_parser->tag_name.data, "br", 2) == 0) {
+ parse_userdata.result += '\n';
+ } else */if(html_parser->tag_name.size == 4 && memcmp(html_parser->tag_name.data, "font", 4) == 0) {
+ parse_userdata.inside_font_tag = false;
+ parse_userdata.font_tag_has_custom_color = false;
+ } else if(html_parser->tag_name.size == 8 && memcmp(html_parser->tag_name.data, "mx-reply", 8) == 0) {
+ parse_userdata.mx_reply_depth = std::max(0, parse_userdata.mx_reply_depth - 1);
+ } else if(html_parser->tag_name.size == 4 && memcmp(html_parser->tag_name.data, "code", 4) == 0) {
+ parse_userdata.inside_code_tag = false;
+ }
+ break;
+ }
+ case HTML_PARSE_ATTRIBUTE: {
+ if(parse_userdata.inside_font_tag && html_parser->attribute_key.size == 5 && memcmp(html_parser->attribute_key.data, "color", 5) == 0) {
+ if(parse_hex_set_color(html_parser->attribute_value.data, html_parser->attribute_value.size, parse_userdata.font_color))
+ parse_userdata.font_tag_has_custom_color = true;
+ }
+ break;
+ }
+ case HTML_PARSE_TEXT:
+ case HTML_PARSE_JAVASCRIPT_CODE: {
+ if(parse_userdata.mx_reply_depth == 0) {
+ std::string text_to_add(html_parser->text.data, html_parser->text.size);
+ html_unescape_sequences(text_to_add);
+
+ uint8_t formatted_text_flags = FORMATTED_TEXT_FLAG_NONE;
+ if(parse_userdata.font_tag_has_custom_color)
+ formatted_text_flags |= FORMATTED_TEXT_FLAG_COLOR;
+ if(parse_userdata.inside_code_tag)
+ formatted_text_flags |= FORMATTED_TEXT_FLAG_MONOSPACE;
+
+ if(formatted_text_flags != FORMATTED_TEXT_FLAG_NONE)
+ parse_userdata.result += Text::formatted_text(text_to_add, parse_userdata.font_color, formatted_text_flags);
+ else
+ parse_userdata.result += std::move(text_to_add);
+ }
+ break;
+ }
+ }
+ return 0;
+ }
+
+ std::string formatted_text_to_qm_text(const char *str, size_t size) {
+ FormattedTextParseUserdata parse_userdata;
+ html_parser_parse(str, size, formattext_text_parser_callback, &parse_userdata);
+ return std::move(parse_userdata.result);
+ }
+
std::shared_ptr<Message> Matrix::parse_message_event(const rapidjson::Value &event_item_json, RoomData *room_data) {
if(!event_item_json.IsObject())
return nullptr;
@@ -2612,6 +2722,10 @@ namespace QuickMedia {
if(!body_json.IsString())
return nullptr;
+ const rapidjson::Value *formatted_body_json = &GetMember(*content_json, "formatted_body");
+ if(!formatted_body_json->IsString())
+ formatted_body_json = &body_json;
+
auto message = std::make_shared<Message>();
std::string prefix;
@@ -2678,7 +2792,7 @@ namespace QuickMedia {
message->user = user;
message->event_id = event_id_str;
- message->body = prefix + body_json.GetString();
+ message->body = prefix + std::string(formatted_body_json->GetString(), formatted_body_json->GetStringLength());
message->related_event_id = std::move(related_event_id);
message->related_event_type = related_event_type;
message->timestamp = timestamp;