aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--TODO5
-rw-r--r--plugins/Matrix.hpp19
-rw-r--r--src/QuickMedia.cpp65
-rw-r--r--src/plugins/Matrix.cpp130
4 files changed, 181 insertions, 38 deletions
diff --git a/TODO b/TODO
index 906525d..6821418 100644
--- a/TODO
+++ b/TODO
@@ -85,7 +85,6 @@ then add a gap between old messages from before sync and after sync so we can fe
Fetching of previous messages should also be saved in the /sync file and messages fetched with get_message_by_id, which would cache embedded items and pinned messages; also cache users.
If manga page fails to download then show "failed to download image" as text and bind F5 to refresh (retry download).
Use <img src to add custom emojis, and add setting for adding/removing custom emoji.
-Set window title when room name changes in matrix.
Create multiple BodyItem types. BodyItem has a lot of fields and most of them are not always used.
Remove display names from reactions if there are many reactions, and instead group them into: reaction (#number of this type of reaction); for example: 👍 2.
Make reaction and deleted message provisional.
@@ -106,7 +105,6 @@ Cloudflare kicks in when downloading manga on manganelo.. figure out a way to by
Replace cppcodec with another library for base64 url encoding/decoding. Its way too large for what it does.
Revert back to old fuzzy search code or use levenshtein distance, then reorder items by best match. This could be done by having a second vector of indices and use that vector everywhere body items by index is accessed (including selected_item). Also perform the search in Body::draw when search term has been modified. This allows us to automatically update that new vector.
Update subscriptions page either with f5 and automatically update it when adding/removing subscriptions.
-Update room name and topic text in ui when they change.
Support webp directly without using ffmpeg to convert it to a png.
Add client side 4chan file size limit (note, webm has different limit than images).
Add client side 4chan max comment chars limit.
@@ -169,7 +167,7 @@ Synapse is gay and mentions do not actually include the whole mxid. It only incl
Make it possible to redact invites.
Reapply filter when changing body item text.
When fetching previous messages in matrix, ignore user info updates.
-Use event timestamp to sort display name/room name (etc) events to apply them in order when fetching previous messages or additional messages.
+Use event timestamp to sort events to apply them in order when fetching previous messages or additional messages.
Try to reconnect media proxy on disconnect. The internet may be unstable (for example on mobile internet).
Opening a media url should display it directly in quickmedia.
Automatically resize body item thumbnail if body is small, or move thumbnail above the text.
@@ -237,7 +235,6 @@ Add proper vim modal mode. Maybe switch focused part with tab? then also need to
Send clipboard content to clipboard manager when destroying the window, if we are the clipboard owner.
Bypass compositor when fullscreening application.
Sort matrix events by timestamp. This is needed to make name change and other similar things work properly, otherwise @ mention wont work as it may show an older name if a previous event is fetched and contains name change. Also applies to join/leave events and other things.
-Update room name, avatar, etc in gui when updated.
Automatically cleanup old cache files.
Download manga pages in parallel. This helps downloading for certain websites such as mangakatana where a single page can take more than 2 seconds but loading 5 at once allows each page to load in 0.4 seconds.
Allow pasting a file link (with or without file://) directly into matrix chat to upload a file (if the chat input is empty). This allows replying-with-media to work with ctrl+v.
diff --git a/plugins/Matrix.hpp b/plugins/Matrix.hpp
index b7d6d66..11989e3 100644
--- a/plugins/Matrix.hpp
+++ b/plugins/Matrix.hpp
@@ -78,10 +78,18 @@ namespace QuickMedia {
std::optional<std::string> avatar_url;
};
+ struct MatrixEventRoomInfo {
+ RoomData *room;
+ std::optional<std::string> name;
+ std::optional<std::string> topic;
+ std::optional<std::string> avatar_url;
+ };
+
enum class MatrixEventType {
ADD_USER,
REMOVE_USER,
- USER_INFO
+ USER_INFO,
+ ROOM_INFO
};
struct Message {
@@ -272,6 +280,7 @@ namespace QuickMedia {
virtual void add_user(MatrixEventUserInfo user_info) = 0;
virtual void remove_user(MatrixEventUserInfo user_info) = 0;
virtual void set_user_info(MatrixEventUserInfo user_info) = 0;
+ virtual void set_room_info(MatrixEventRoomInfo room_info) = 0;
virtual void clear_data() = 0;
};
@@ -303,6 +312,7 @@ namespace QuickMedia {
void add_user(MatrixEventUserInfo user_info) override;
void remove_user(MatrixEventUserInfo user_info) override;
void set_user_info(MatrixEventUserInfo user_info) override;
+ void set_room_info(MatrixEventRoomInfo room_info) override;
void for_each_user_in_room(RoomData *room, std::function<void(const MatrixEventUserInfo&)> callback);
void set_room_as_read(RoomData *room);
@@ -430,6 +440,8 @@ namespace QuickMedia {
std::string filename;
};
+ using MatrixRoomInfoUpdateCallback = std::function<void(const MatrixEventRoomInfo &room_info)>;
+
class MatrixChatPage : public Page {
public:
MatrixChatPage(Program *program, std::string room_id, MatrixRoomsPage *rooms_page, std::string jump_to_event_id = "");
@@ -441,8 +453,9 @@ namespace QuickMedia {
void add_user(MatrixEventUserInfo user_info);
void remove_user(MatrixEventUserInfo user_info);
void set_user_info(MatrixEventUserInfo user_info);
+ void set_room_info(MatrixEventRoomInfo room_info);
- void set_current_room(RoomData *room, Body *users_body);
+ void set_current_room(RoomData *room, Body *users_body, MatrixRoomInfoUpdateCallback room_info_update_callback);
size_t get_num_users_in_current_room() const;
void set_room_as_read(RoomData *room);
@@ -458,6 +471,7 @@ namespace QuickMedia {
private:
RoomData *current_room = nullptr;
Body *users_body = nullptr;
+ MatrixRoomInfoUpdateCallback room_info_update_callback;
};
class MatrixRoomDirectoryPage : public Page {
@@ -609,6 +623,7 @@ namespace QuickMedia {
void update();
private:
void trigger_event(RoomData *room, MatrixEventType type, MatrixEventUserInfo user_info);
+ void trigger_event(RoomData *room, MatrixEventType type, MatrixEventRoomInfo room_info);
void formatted_body_add_line(RoomData *room, std::string &formatted_body, const std::string &line_str);
void replace_mentions(RoomData *room, std::string &text);
diff --git a/src/QuickMedia.cpp b/src/QuickMedia.cpp
index fbf2006..432dccb 100644
--- a/src/QuickMedia.cpp
+++ b/src/QuickMedia.cpp
@@ -5462,6 +5462,23 @@ namespace QuickMedia {
bool move_room = false;
+ const float room_name_text_height = std::floor(18.0f * get_config().scale * get_config().font_scale);
+ mgl::Text room_name_text("", *FontLoader::get_font(FontLoader::FontType::LATIN_BOLD, room_name_text_height));
+ const float room_name_text_padding_y = std::floor(10.0f * get_config().scale);
+ const float room_name_total_height = room_name_text_height + room_name_text_padding_y * 2.0f;
+ const float room_avatar_height = 32.0f;
+
+ const float room_topic_text_height = std::floor(12.0f * get_config().scale * get_config().font_scale);
+ mgl::Text room_topic_text("", *FontLoader::get_font(FontLoader::FontType::LATIN, room_topic_text_height));
+ room_topic_text.set_color(get_theme().faded_text_color);
+
+ mgl::Text room_label(matrix_chat_page->rooms_page->get_title(), *FontLoader::get_font(FontLoader::FontType::LATIN_BOLD, 18 * get_config().scale * get_config().font_scale));
+ room_label.set_position(mgl::vec2f(15.0f, room_name_text_padding_y + 4.0f));
+
+ mgl::Sprite room_avatar_sprite;
+ auto room_avatar_thumbnail_data = std::make_shared<ThumbnailData>();
+ bool avatar_applied = false;
+
std::vector<ChatTab> tabs;
ChatTab pinned_tab;
@@ -5494,7 +5511,27 @@ namespace QuickMedia {
matrix_chat_page->chat_body = tabs[MESSAGES_TAB_INDEX].body.get();
matrix_chat_page->messages_tab_visible = true;
- matrix_chat_page->set_current_room(current_room, tabs[USERS_TAB_INDEX].body.get());
+ matrix_chat_page->set_current_room(current_room, tabs[USERS_TAB_INDEX].body.get(),
+ [&](const MatrixEventRoomInfo &room_info) {
+ if(room_info.name) {
+ window.set_title(("QuickMedia - matrix - " + room_info.name.value()).c_str());
+ std::string room_name = current_room->get_name();
+ string_replace_all(room_name, '\n', ' ');
+ room_name_text.set_string(std::move(room_name));
+ }
+
+ if(room_info.topic) {
+ std::string room_topic = current_room->get_topic();
+ string_replace_all(room_topic, '\n', ' ');
+ room_topic_text.set_string(std::move(room_topic));
+ }
+
+ if(room_info.avatar_url) {
+ room_avatar_sprite.set_texture(nullptr);
+ room_avatar_thumbnail_data.reset();
+ avatar_applied = false;
+ }
+ });
size_t prev_num_users_in_room = 0;
bool redraw = true;
@@ -5560,22 +5597,6 @@ namespace QuickMedia {
logo_sprite.set_scale(mgl::vec2f(0.8f * get_config().scale, 0.8f * get_config().scale));
mgl::vec2f logo_size(plugin_logo.get_size().x * logo_sprite.get_scale().x, plugin_logo.get_size().y * logo_sprite.get_scale().y);
- const float room_name_text_height = std::floor(18.0f * get_config().scale * get_config().font_scale);
- mgl::Text room_name_text("", *FontLoader::get_font(FontLoader::FontType::LATIN_BOLD, room_name_text_height));
- const float room_name_text_padding_y = std::floor(10.0f * get_config().scale);
- const float room_name_total_height = room_name_text_height + room_name_text_padding_y * 2.0f;
- const float room_avatar_height = 32.0f;
-
- const float room_topic_text_height = std::floor(12.0f * get_config().scale * get_config().font_scale);
- mgl::Text room_topic_text("", *FontLoader::get_font(FontLoader::FontType::LATIN, room_topic_text_height));
- room_topic_text.set_color(get_theme().faded_text_color);
-
- mgl::Text room_label(matrix_chat_page->rooms_page->get_title(), *FontLoader::get_font(FontLoader::FontType::LATIN_BOLD, 18 * get_config().scale * get_config().font_scale));
- room_label.set_position(mgl::vec2f(15.0f, room_name_text_padding_y + 4.0f));
-
- mgl::Sprite room_avatar_sprite;
- auto room_avatar_thumbnail_data = std::make_shared<ThumbnailData>();
-
bool draw_room_list = show_room_side_panel;
// TODO: What if these never end up referencing events? clean up automatically after a while?
@@ -6364,8 +6385,6 @@ namespace QuickMedia {
const float logo_padding_x = std::floor(10.0f * get_config().scale * get_config().spacing_scale);
const float chat_input_padding_x = std::floor(10.0f * get_config().scale * get_config().spacing_scale);
const float chat_input_padding_y = std::floor(10.0f * get_config().scale * get_config().spacing_scale);
-
- bool avatar_applied = false;
auto jump_to_message = [&](const std::string &event_id) {
const int selected_tab = ui_tabs.get_selected();
@@ -7245,7 +7264,7 @@ namespace QuickMedia {
break;
}
case PageType::CHAT_LOGIN: {
- matrix_chat_page->set_current_room(nullptr, nullptr);
+ matrix_chat_page->set_current_room(nullptr, nullptr, nullptr);
fetch_messages_future.cancel();
cleanup_tasks();
tabs.clear();
@@ -7660,7 +7679,7 @@ namespace QuickMedia {
if(matrix && !matrix->is_initial_sync_finished()) {
std::string err_msg;
if(matrix->did_initial_sync_fail(err_msg)) {
- matrix_chat_page->set_current_room(nullptr, nullptr);
+ matrix_chat_page->set_current_room(nullptr, nullptr, nullptr);
fetch_messages_future.cancel();
cleanup_tasks();
tabs.clear();
@@ -7696,7 +7715,7 @@ namespace QuickMedia {
while(!matrix->is_initial_sync_finished()) {
std::this_thread::sleep_for(std::chrono::milliseconds(10));
if(matrix->did_initial_sync_fail(err_msg)) {
- matrix_chat_page->set_current_room(nullptr, nullptr);
+ matrix_chat_page->set_current_room(nullptr, nullptr, nullptr);
fetch_messages_future.cancel();
cleanup_tasks();
tabs.clear();
@@ -7753,7 +7772,7 @@ namespace QuickMedia {
}
chat_page_end:
- matrix_chat_page->set_current_room(nullptr, nullptr);
+ matrix_chat_page->set_current_room(nullptr, nullptr, nullptr);
fetch_messages_future.cancel();
cleanup_tasks();
window.set_title("QuickMedia - matrix");
diff --git a/src/plugins/Matrix.cpp b/src/plugins/Matrix.cpp
index 7318383..db37a97 100644
--- a/src/plugins/Matrix.cpp
+++ b/src/plugins/Matrix.cpp
@@ -510,6 +510,25 @@ namespace QuickMedia {
chat_page->set_user_info(std::move(user_info));
}
+ void MatrixQuickMedia::set_room_info(MatrixEventRoomInfo room_info) {
+ auto it = room_body_item_by_room.find(room_info.room);
+ if(it == room_body_item_by_room.end())
+ return;
+
+ if(room_info.name) {
+ std::string room_name = room_info.name.value_or(room_info.room->id);
+ string_replace_all(room_name, '\n', ' ');
+ it->second->set_title(std::move(room_name));
+ //body_item->thumbnail_url = room->get_avatar_url();
+ }
+
+ if(room_info.avatar_url)
+ it->second->thumbnail_url = room_info.avatar_url.value();
+
+ if(chat_page)
+ chat_page->set_room_info(std::move(room_info));
+ }
+
void MatrixQuickMedia::for_each_user_in_room(RoomData *room, std::function<void(const MatrixEventUserInfo&)> callback) {
auto &users = users_by_room[room];
for(const auto &user : users) {
@@ -980,9 +999,17 @@ namespace QuickMedia {
}
}
- void MatrixChatPage::set_current_room(RoomData *room, Body *users_body) {
+ void MatrixChatPage::set_room_info(MatrixEventRoomInfo room_info) {
+ if(!current_room || !room_info_update_callback || room_info.room != current_room)
+ return;
+
+ room_info_update_callback(room_info);
+ }
+
+ void MatrixChatPage::set_current_room(RoomData *room, Body *users_body, MatrixRoomInfoUpdateCallback room_info_update_callback) {
this->current_room = room;
this->users_body = users_body;
+ this->room_info_update_callback = std::move(room_info_update_callback);
if(!room || !users_body)
return;
@@ -2521,6 +2548,53 @@ namespace QuickMedia {
message->timestamp = timestamp;
message->transaction_id = std::move(transaction_id);
return message;
+ } else if(strcmp(type_json.GetString(), "m.room.name") == 0) {
+ std::string sender_display_name = extract_first_line_remove_newline_elipses(room_data->get_user_display_name(user_sender), AUTHOR_MAX_LENGTH);
+ const rapidjson::Value &new_room_name = GetMember(*content_json, "name");
+
+ auto message = std::make_shared<Message>();
+ message->type = MessageType::SYSTEM;
+ message->user = user;
+ message->event_id = event_id_str;
+ if(new_room_name.IsString() && new_room_name.GetStringLength() > 0)
+ message->body = sender_display_name + " changed the room name to \"" + new_room_name.GetString() + "\"";
+ else
+ message->body = sender_display_name + " removed the room name";
+ message->related_event_id = std::move(related_event_id);
+ message->related_event_type = related_event_type;
+ message->timestamp = timestamp;
+ message->transaction_id = std::move(transaction_id);
+ return message;
+ } else if(strcmp(type_json.GetString(), "m.room.topic") == 0) {
+ std::string sender_display_name = extract_first_line_remove_newline_elipses(room_data->get_user_display_name(user_sender), AUTHOR_MAX_LENGTH);
+ const rapidjson::Value &new_room_topic = GetMember(*content_json, "topic");
+
+ auto message = std::make_shared<Message>();
+ message->type = MessageType::SYSTEM;
+ message->user = user;
+ message->event_id = event_id_str;
+ if(new_room_topic.IsString() && new_room_topic.GetStringLength() > 0)
+ message->body = sender_display_name + " changed the room topic to \"" + new_room_topic.GetString() + "\"";
+ else
+ message->body = sender_display_name + " removed the room topic";
+ message->related_event_id = std::move(related_event_id);
+ message->related_event_type = related_event_type;
+ message->timestamp = timestamp;
+ message->transaction_id = std::move(transaction_id);
+ return message;
+ } else if(strcmp(type_json.GetString(), "m.room.avatar") == 0) {
+ std::string sender_display_name = extract_first_line_remove_newline_elipses(room_data->get_user_display_name(user_sender), AUTHOR_MAX_LENGTH);
+
+ auto message = std::make_shared<Message>();
+ message->type = MessageType::SYSTEM;
+ message->user = user;
+ message->event_id = event_id_str;
+ message->body = sender_display_name + " changed the room avatar";
+ message->related_event_id = std::move(related_event_id);
+ message->related_event_type = related_event_type;
+ message->timestamp = timestamp;
+ message->transaction_id = std::move(transaction_id);
+ return message;
} else {
auto message = std::make_shared<Message>();
message->type = MessageType::UNIMPLEMENTED;
@@ -2637,6 +2711,10 @@ namespace QuickMedia {
if(!events_json.IsArray())
return;
+ bool update_room_name = false;
+ bool update_room_topic = false;
+ bool update_room_avatar_url = false;
+
for(const rapidjson::Value &event_item_json : events_json.GetArray()) {
if(!event_item_json.IsObject())
continue;
@@ -2661,7 +2739,7 @@ namespace QuickMedia {
if(!name_json.IsString())
continue;
- room_data->set_name(name_json.GetString(), item_timestamp); // TODO: Update room name in gui
+ update_room_name |= room_data->set_name(name_json.GetString(), item_timestamp);
room_data->name_is_fallback = false;
} else if(strcmp(type_json.GetString(), "m.room.avatar") == 0) {
const rapidjson::Value &content_json = GetMember(event_item_json, "content");
@@ -2672,7 +2750,7 @@ namespace QuickMedia {
if(!url_json.IsString() || strncmp(url_json.GetString(), "mxc://", 6) != 0)
continue;
- room_data->set_avatar_url(get_thumbnail_url(homeserver, thumbnail_url_extract_media_id(url_json.GetString())), item_timestamp); // TODO: Update avatar url in gui
+ update_room_avatar_url |= room_data->set_avatar_url(get_thumbnail_url(homeserver, thumbnail_url_extract_media_id(url_json.GetString())), item_timestamp);
room_data->avatar_is_fallback = false;
} else if(strcmp(type_json.GetString(), "m.room.topic") == 0) {
const rapidjson::Value &content_json = GetMember(event_item_json, "content");
@@ -2683,21 +2761,32 @@ namespace QuickMedia {
if(!topic_json.IsString())
continue;
- room_data->set_topic(topic_json.GetString(), item_timestamp); // TODO: Update topic in gui
+ update_room_topic |= room_data->set_topic(topic_json.GetString(), item_timestamp);
}
}
+
+ MatrixEventRoomInfo room_info_event;
+ room_info_event.room = room_data;
+ room_info_event.name = update_room_name ? std::optional<std::string>(room_data->get_name()) : std::nullopt;
+ room_info_event.topic = update_room_topic ? std::optional<std::string>(room_data->get_topic()) : std::nullopt;
+ room_info_event.avatar_url = update_room_avatar_url ? std::optional<std::string>(room_data->get_avatar_url()) : std::nullopt;
+ if(update_room_name || update_room_topic || update_room_avatar_url)
+ trigger_event(room_data, MatrixEventType::ROOM_INFO, std::move(room_info_event));
}
void Matrix::set_room_info_to_users_if_empty(RoomData *room, const std::string &room_creator_user_id) {
- bool has_room_name = room->has_name();
- bool has_room_avatar_url = room->has_avatar_url();
+ const bool has_room_name = room->has_name();
+ const bool has_room_avatar_url = room->has_avatar_url();
+
+ bool update_room_name = false;
+ bool update_room_avatar_url = false;
std::vector<std::shared_ptr<UserInfo>> users_excluding_me;
if(!has_room_name || !has_room_avatar_url || room->name_is_fallback || room->avatar_is_fallback)
users_excluding_me = room->get_users_excluding_me(my_user_id);
if(!has_room_name) {
- room->set_name(combine_user_display_names_for_room_name(users_excluding_me, room_creator_user_id), 0); // TODO: Update in gui
+ update_room_name |= room->set_name(combine_user_display_names_for_room_name(users_excluding_me, room_creator_user_id), 0);
room->name_is_fallback = true;
}
@@ -2705,13 +2794,20 @@ namespace QuickMedia {
if(users_excluding_me.empty()) {
auto user = get_user_by_id(room, room_creator_user_id);
if(user)
- room->set_avatar_url(room->get_user_avatar_url(user), 0); // TODO: Update in gui
+ update_room_avatar_url |= room->set_avatar_url(room->get_user_avatar_url(user), 0);
} else {
// TODO: If there are multiple users, then we want to use some other type of avatar, not the first users avatar
- room->set_avatar_url(room->get_user_avatar_url(users_excluding_me.front()), 0); // TODO: Update in gui
+ update_room_avatar_url |= room->set_avatar_url(room->get_user_avatar_url(users_excluding_me.front()), 0);
}
room->avatar_is_fallback = true;
}
+
+ MatrixEventRoomInfo room_info_event;
+ room_info_event.room = room;
+ room_info_event.name = update_room_name ? std::optional<std::string>(room->get_name()) : std::nullopt;
+ room_info_event.avatar_url = update_room_avatar_url ? std::optional<std::string>(room->get_avatar_url()) : std::nullopt;
+ if(update_room_name || update_room_avatar_url)
+ trigger_event(room, MatrixEventType::ROOM_INFO, std::move(room_info_event));
}
void Matrix::events_add_pinned_events(const rapidjson::Value &events_json, RoomData *room_data) {
@@ -4902,6 +4998,22 @@ namespace QuickMedia {
});
break;
}
+ default:
+ break;
+ }
+ }
+
+ void Matrix::trigger_event(RoomData *room, MatrixEventType type, MatrixEventRoomInfo room_info) {
+ room_info.room = room;
+ switch(type) {
+ case MatrixEventType::ROOM_INFO: {
+ ui_thread_tasks.push([this, room_info{std::move(room_info)}]{
+ delegate->set_room_info(std::move(room_info));
+ });
+ break;
+ }
+ default:
+ break;
}
}
} \ No newline at end of file