aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--TODO3
-rw-r--r--include/Body.hpp12
-rw-r--r--plugins/Matrix.hpp74
-rw-r--r--src/Body.cpp14
-rw-r--r--src/QuickMedia.cpp118
-rw-r--r--src/plugins/Matrix.cpp231
6 files changed, 249 insertions, 203 deletions
diff --git a/TODO b/TODO
index 4bdbdbb..07ac0b8 100644
--- a/TODO
+++ b/TODO
@@ -126,4 +126,5 @@ Dynamically fetch 4chan api key, if it ever changes in the future. Same for yout
Set curl download limits everywhere (when saving to file, downloading to json, etc...).
In the downloader if we already have the url in thumbnail/video cache, then copy it to the destination instead of redownloading it. This would also fix downloading images when viewing a manga page.
Update timestamp of messages posted with matrix (and move them to the correct place in the timeline) when we receive the message from the server. This is needed when the localtime is messed up (for example when rebooting from windows into linux).
-Remove dependency on imagemagick and create a function that forks the processes and creates a thumbnail from an input filepath and output filepath. That new process can use sf::Image to load and save the images. \ No newline at end of file
+Remove dependency on imagemagick and create a function that forks the processes and creates a thumbnail from an input filepath and output filepath. That new process can use sf::Image to load and save the images.
+Youtube now requires signing in to view age restricted content. For such videos quickmedia should fallback to invidious. \ No newline at end of file
diff --git a/include/Body.hpp b/include/Body.hpp
index 8e571f1..0b0fca4 100644
--- a/include/Body.hpp
+++ b/include/Body.hpp
@@ -246,7 +246,9 @@ namespace QuickMedia {
int get_num_visible_items() const { return num_visible_items; };
// Call this once after adding new items
- void items_set_dirty();
+ void items_set_dirty(bool force = false);
+
+ void apply_search_filter_for_item(BodyItem *body_item);
sf::Text progress_text;
sf::Text replies_text;
@@ -279,6 +281,12 @@ namespace QuickMedia {
float get_offset_to_first_visible_item(sf::Vector2f body_size);
float get_offset_to_last_visible_item(sf::Vector2f body_size);
private:
+ enum class DirtyState {
+ FALSE,
+ TRUE,
+ FORCE_TRUE
+ };
+
Program *program;
int selected_item;
int prev_selected_item;
@@ -329,7 +337,7 @@ namespace QuickMedia {
float item_background_target_pos_y = 0.0f;
float item_background_target_height = 0.0f;
// TODO: Instead of using this, add functions for modifying |items| and apply the filter on those new items
- bool items_dirty = false;
+ DirtyState items_dirty = DirtyState::FALSE;
std::string current_filter;
bool using_filter = false;
};
diff --git a/plugins/Matrix.hpp b/plugins/Matrix.hpp
index 9d6f0b6..bff89b2 100644
--- a/plugins/Matrix.hpp
+++ b/plugins/Matrix.hpp
@@ -58,41 +58,16 @@ namespace QuickMedia {
};
struct MatrixEventUserInfo {
+ RoomData *room;
std::string user_id;
std::optional<std::string> display_name;
std::optional<std::string> avatar_url;
};
- class MatrixEvent {
- public:
- enum class Type {
- ADD_USER,
- REMOVE_USER,
- USER_INFO
- };
-
- MatrixEvent(Type type) : type(type) {}
- virtual ~MatrixEvent() = default;
-
- const Type type;
- };
-
- class MatrixAddUserEvent : public MatrixEvent {
- public:
- MatrixAddUserEvent(MatrixEventUserInfo user_info) : MatrixEvent(Type::ADD_USER), user_info(std::move(user_info)) {}
- const MatrixEventUserInfo user_info;
- };
-
- class MatrixRemoveUserEvent : public MatrixEvent {
- public:
- MatrixRemoveUserEvent(MatrixEventUserInfo user_info) : MatrixEvent(Type::REMOVE_USER), user_info(std::move(user_info)) {}
- const MatrixEventUserInfo user_info;
- };
-
- class MatrixUserInfoEvent : public MatrixEvent {
- public:
- MatrixUserInfoEvent(MatrixEventUserInfo user_info) : MatrixEvent(Type::USER_INFO), user_info(std::move(user_info)) {}
- const MatrixEventUserInfo user_info;
+ enum class MatrixEventType {
+ ADD_USER,
+ REMOVE_USER,
+ USER_INFO
};
struct Message {
@@ -271,6 +246,10 @@ namespace QuickMedia {
virtual void add_unread_notification(RoomData *room, std::string event_id, std::string sender, std::string body) = 0;
+ 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 clear_data() = 0;
};
@@ -280,6 +259,8 @@ namespace QuickMedia {
class MatrixInvitesPage;
class MatrixChatPage;
+ using UsersByRoom = std::unordered_multimap<RoomData*, MatrixEventUserInfo>;
+
class MatrixQuickMedia : public MatrixDelegate {
public:
MatrixQuickMedia(Program *program, Matrix *matrix, MatrixRoomsPage *rooms_page, MatrixRoomTagsPage *room_tags_page, MatrixInvitesPage *invites_page);
@@ -295,6 +276,11 @@ namespace QuickMedia {
void add_unread_notification(RoomData *room, std::string event_id, std::string sender, std::string body) override;
+ void add_user(MatrixEventUserInfo user_info) override;
+ void remove_user(MatrixEventUserInfo user_info) override;
+ void set_user_info(MatrixEventUserInfo user_info) override;
+ void for_each_user_in_room(RoomData *room, std::function<void(const MatrixEventUserInfo&)> callback);
+
void clear_data() override;
Program *program;
@@ -308,6 +294,7 @@ namespace QuickMedia {
private:
std::map<RoomData*, std::shared_ptr<BodyItem>> room_body_item_by_room;
std::map<RoomData*, std::shared_ptr<Message>> last_message_by_room;
+ UsersByRoom users_by_room;
};
class MatrixRoomsPage : public Page {
@@ -319,6 +306,7 @@ namespace QuickMedia {
PluginResult submit(const std::string &title, const std::string &url, std::vector<Tab> &result_tabs) override;
bool submit_is_async() override { return false; }
bool clear_search_after_submit() override { return true; }
+ void on_navigate_to_page(Body *body) override;
void add_body_item(std::shared_ptr<BodyItem> body_item);
@@ -344,6 +332,7 @@ namespace QuickMedia {
PluginResult submit(const std::string &title, const std::string &url, std::vector<Tab> &result_tabs) override;
bool submit_is_async() override { return false; }
bool clear_search_after_submit() override { return true; }
+ void on_navigate_to_page(Body *body) override;
void add_room_body_item_to_tag(std::shared_ptr<BodyItem> body_item, const std::string &tag);
void remove_room_body_item_from_tag(std::shared_ptr<BodyItem> body_item, const std::string &tag);
@@ -423,12 +412,22 @@ namespace QuickMedia {
const char* get_title() const override { return ""; }
PageTypez get_type() const override { return PageTypez::CHAT; }
+ void add_user(MatrixEventUserInfo user_info);
+ void remove_user(MatrixEventUserInfo user_info);
+ void set_user_info(MatrixEventUserInfo user_info);
+
+ void set_current_room(RoomData *room, Body *users_body);
+ size_t get_num_users_in_current_room() const;
+
const std::string room_id;
MatrixRoomsPage *rooms_page = nullptr;
bool should_clear_data = false;
Body *chat_body = nullptr;
bool messages_tab_visible = false;
+ private:
+ RoomData *current_room = nullptr;
+ Body *users_body = nullptr;
};
class MatrixRoomDirectoryPage : public Page {
@@ -533,21 +532,11 @@ namespace QuickMedia {
RoomData* get_room_by_id(const std::string &id);
void update_room_users(RoomData *room);
- // Only one room can have event queue enabled at once
- void enable_event_queue(RoomData *room);
- // Also clears the event queue
- void disable_event_queue();
-
// Calls the |MatrixDelegate| pending events.
// Should be called from the main (ui) thread
void update();
-
- // Has to be called in the main thread.
- // Returns nullptr if there are no new events.
- std::unique_ptr<MatrixEvent> pop_event();
private:
- // No-op if sync is cache or if |room| is not the currently enabled event queue room
- void trigger_event(RoomData *room, std::unique_ptr<MatrixEvent> event);
+ void trigger_event(RoomData *room, MatrixEventType type, MatrixEventUserInfo user_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);
@@ -587,9 +576,6 @@ namespace QuickMedia {
std::string get_filter_cached();
private:
MessageQueue<std::function<void()>> ui_thread_tasks;
- std::deque<std::unique_ptr<MatrixEvent>> event_queue;
- std::mutex event_queue_mutex;
- RoomData *current_event_queue_room = nullptr;
std::vector<std::unique_ptr<RoomData>> rooms;
std::unordered_map<std::string, size_t> room_data_by_id; // value is an index into |rooms|
std::recursive_mutex room_data_mutex;
diff --git a/src/Body.cpp b/src/Body.cpp
index d51ea29..72974fa 100644
--- a/src/Body.cpp
+++ b/src/Body.cpp
@@ -487,10 +487,10 @@ namespace QuickMedia {
// TODO: Use a render target for the whole body so all images can be put into one.
// TODO: Load thumbnails with more than one thread.
void Body::draw(sf::RenderWindow &window, sf::Vector2f pos, sf::Vector2f size, const Json::Value &content_progress) {
- if(items_dirty) {
- items_dirty = false;
- if(using_filter)
+ if(items_dirty != DirtyState::FALSE) {
+ if(using_filter || items_dirty == DirtyState::FORCE_TRUE)
filter_search_fuzzy(current_filter, false);
+ items_dirty = DirtyState::FALSE;
}
sf::Vector2f scissor_pos = pos;
@@ -1547,7 +1547,11 @@ namespace QuickMedia {
clamp_selected_item_to_body_count = 1;
}
- void Body::items_set_dirty() {
- items_dirty = true;
+ void Body::items_set_dirty(bool force) {
+ items_dirty = force ? DirtyState::FORCE_TRUE : DirtyState::TRUE;
+ }
+
+ void Body::apply_search_filter_for_item(BodyItem *body_item) {
+ filter_search_fuzzy_item(current_filter, body_item);
}
}
diff --git a/src/QuickMedia.cpp b/src/QuickMedia.cpp
index 5bbcfd7..a9956d3 100644
--- a/src/QuickMedia.cpp
+++ b/src/QuickMedia.cpp
@@ -3952,11 +3952,13 @@ namespace QuickMedia {
Tabs ui_tabs(&rounded_rectangle_shader, sf::Color::Transparent);
const int PINNED_TAB_INDEX = ui_tabs.add_tab("Pinned messages (0)");
const int MESSAGES_TAB_INDEX = ui_tabs.add_tab("Messages");
- const int USERS_TAB_INDEX = ui_tabs.add_tab("Users");
+ const int USERS_TAB_INDEX = ui_tabs.add_tab("Users (0)");
ui_tabs.set_selected(MESSAGES_TAB_INDEX);
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());
+ size_t prev_num_users_in_room = 0;
bool redraw = true;
@@ -4994,91 +4996,6 @@ namespace QuickMedia {
//tabs.clear();
};
- auto on_add_user_event = [&ui_tabs, &tabs, USERS_TAB_INDEX](MatrixAddUserEvent *event) {
- // Ignore if the user already exists in the room
- // TODO: Remove the need for this
- for(auto &body_item : tabs[USERS_TAB_INDEX].body->items) {
- if(body_item->url == event->user_info.user_id)
- return;
- }
-
- std::string display_name = event->user_info.display_name.value_or(event->user_info.user_id);
- size_t insert_position = get_body_item_sorted_insert_position_by_author(tabs[USERS_TAB_INDEX].body->items, display_name, 0);
-
- auto body_item = BodyItem::create("");
- body_item->url = event->user_info.user_id;
- body_item->set_author(std::move(display_name));
- body_item->set_author_color(user_id_to_color(event->user_info.user_id));
- body_item->set_description(event->user_info.user_id);
- body_item->set_description_color(sf::Color(179, 179, 179));
- if(event->user_info.avatar_url)
- body_item->thumbnail_url = event->user_info.avatar_url.value();
- body_item->thumbnail_mask_type = ThumbnailMaskType::CIRCLE;
- body_item->thumbnail_size = AVATAR_THUMBNAIL_SIZE;
- tabs[USERS_TAB_INDEX].body->items.insert(tabs[USERS_TAB_INDEX].body->items.begin() + insert_position, std::move(body_item));
- tabs[USERS_TAB_INDEX].body->items_set_dirty();
-
- ui_tabs.set_text(USERS_TAB_INDEX, "Users (" + std::to_string(tabs[USERS_TAB_INDEX].body->items.size()) + ")");
- };
-
- // TODO: Actually trigger this when a user leaves the room. Also remove the user from the room in the matrix plugin
- auto on_remove_user_event = [&ui_tabs, &tabs, USERS_TAB_INDEX](MatrixRemoveUserEvent *event) {
- for(auto it = tabs[USERS_TAB_INDEX].body->items.begin(), end = tabs[USERS_TAB_INDEX].body->items.end(); it != end; ++it) {
- if((*it)->url == event->user_info.user_id) {
- tabs[USERS_TAB_INDEX].body->items.erase(it);
- ui_tabs.set_text(USERS_TAB_INDEX, "Users (" + std::to_string(tabs[USERS_TAB_INDEX].body->items.size()) + ")");
- return;
- }
- }
- };
-
- auto on_user_info_event = [&tabs, USERS_TAB_INDEX](MatrixUserInfoEvent *event) {
- for(auto it = tabs[USERS_TAB_INDEX].body->items.begin(), end = tabs[USERS_TAB_INDEX].body->items.end(); it != end; ++it) {
- if((*it)->url == event->user_info.user_id) {
- if(event->user_info.avatar_url)
- (*it)->thumbnail_url = event->user_info.avatar_url.value();
-
- if(event->user_info.display_name) {
- std::string display_name;
- if(event->user_info.display_name.value().empty())
- display_name = event->user_info.user_id;
- else
- display_name = event->user_info.display_name.value();
-
- (*it)->set_author(std::move(display_name));
-
- auto user_body_item = *it;
- tabs[USERS_TAB_INDEX].body->items.erase(it);
-
- // TODO: extract_first_line_remove_newline_elipses(room->get_user_display_name(message->user), AUTHOR_MAX_LENGTH),
- // But that should be done in Text because we need author to be 100% the same as in the input to reorder users
- size_t insert_position = get_body_item_sorted_insert_position_by_author(tabs[USERS_TAB_INDEX].body->items, user_body_item->get_author(), 0);
- tabs[USERS_TAB_INDEX].body->items.insert(tabs[USERS_TAB_INDEX].body->items.begin() + insert_position, std::move(user_body_item));
- tabs[USERS_TAB_INDEX].body->items_set_dirty();
- }
-
- return;
- }
- }
- };
-
- matrix->enable_event_queue(current_room);
- {
- auto users_in_room = current_room->get_users();
- for(auto &user : users_in_room) {
- std::string display_name = current_room->get_user_display_name(user);
- std::string avatar_url = current_room->get_user_avatar_url(user);
-
- MatrixEventUserInfo user_info;
- user_info.user_id = user->user_id;
- user_info.display_name = std::move(display_name);
- user_info.avatar_url = std::move(avatar_url);
-
- MatrixAddUserEvent add_user_event(std::move(user_info));
- on_add_user_event(&add_user_event);
- }
- }
-
// TODO: Remove this once synapse bug has been resolved where /sync does not include user info for new messages when using message filter that limits number of messages for initial sync,
// and then only call this when viewing the users tab for the first time.
// Note that this is not needed when new users join the room, as those will be included in the sync timeline (with membership events)
@@ -5390,22 +5307,11 @@ namespace QuickMedia {
matrix->update();
mention.update();
-
- std::unique_ptr<MatrixEvent> matrix_event;
- while((matrix_event = matrix->pop_event()) != nullptr) {
- if(matrix_event) {
- switch(matrix_event->type) {
- case MatrixEvent::Type::ADD_USER:
- on_add_user_event(static_cast<MatrixAddUserEvent*>(matrix_event.get()));
- break;
- case MatrixEvent::Type::REMOVE_USER:
- on_remove_user_event(static_cast<MatrixRemoveUserEvent*>(matrix_event.get()));
- break;
- case MatrixEvent::Type::USER_INFO:
- on_user_info_event(static_cast<MatrixUserInfoEvent*>(matrix_event.get()));
- break;
- }
- }
+
+ const size_t num_users_in_room = matrix_chat_page->get_num_users_in_current_room();
+ if(num_users_in_room != prev_num_users_in_room) {
+ prev_num_users_in_room = num_users_in_room;
+ ui_tabs.set_text(USERS_TAB_INDEX, "Users (" + std::to_string(num_users_in_room) + ")");
}
while((provisional_message = provisional_message_queue.pop_if_available()) != std::nullopt) {
@@ -5451,7 +5357,7 @@ namespace QuickMedia {
break;
}
case PageType::CHAT_LOGIN: {
- matrix->disable_event_queue();
+ matrix_chat_page->set_current_room(nullptr, nullptr);
previous_messages_future.cancel();
cleanup_tasks();
tabs.clear();
@@ -5818,7 +5724,7 @@ namespace QuickMedia {
if(matrix && !matrix->is_initial_sync_finished()) {
std::string err_msg;
if(matrix->did_initial_sync_fail(err_msg)) {
- matrix->disable_event_queue();
+ matrix_chat_page->set_current_room(nullptr, nullptr);
previous_messages_future.cancel();
cleanup_tasks();
tabs.clear();
@@ -5848,7 +5754,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->disable_event_queue();
+ matrix_chat_page->set_current_room(nullptr, nullptr);
previous_messages_future.cancel();
cleanup_tasks();
tabs.clear();
@@ -5899,7 +5805,7 @@ namespace QuickMedia {
}
chat_page_end:
- matrix->disable_event_queue();
+ matrix_chat_page->set_current_room(nullptr, nullptr);
previous_messages_future.cancel();
cleanup_tasks();
window.setTitle("QuickMedia - matrix");
diff --git a/src/plugins/Matrix.cpp b/src/plugins/Matrix.cpp
index 8a0f486..afa8738 100644
--- a/src/plugins/Matrix.cpp
+++ b/src/plugins/Matrix.cpp
@@ -437,6 +437,50 @@ namespace QuickMedia {
show_notification("QuickMedia matrix - " + sender + " (" + room->get_name() + ")", body);
}
+ static UsersByRoom::iterator find_user_data_by_id(UsersByRoom &users_by_room, const MatrixEventUserInfo &user_info) {
+ RoomData *room = user_info.room;
+ auto range = users_by_room.equal_range(room);
+ for(auto &it = range.first; it != range.second; ++it) {
+ if(it->second.user_id == user_info.user_id)
+ return it;
+ }
+ return users_by_room.end();
+ }
+
+ void MatrixQuickMedia::add_user(MatrixEventUserInfo user_info) {
+ auto it = find_user_data_by_id(users_by_room, user_info);
+ if(it == users_by_room.end()) {
+ users_by_room.insert(std::make_pair(user_info.room, user_info));
+ if(chat_page)
+ chat_page->add_user(std::move(user_info));
+ }
+ }
+
+ void MatrixQuickMedia::remove_user(MatrixEventUserInfo user_info) {
+ auto it = find_user_data_by_id(users_by_room, user_info);
+ if(it != users_by_room.end()) {
+ users_by_room.erase(it);
+ if(chat_page)
+ chat_page->remove_user(std::move(user_info));
+ }
+ }
+
+ void MatrixQuickMedia::set_user_info(MatrixEventUserInfo user_info) {
+ auto it = find_user_data_by_id(users_by_room, user_info);
+ if(it != users_by_room.end()) {
+ it->second = user_info;
+ if(chat_page)
+ chat_page->set_user_info(std::move(user_info));
+ }
+ }
+
+ void MatrixQuickMedia::for_each_user_in_room(RoomData *room, std::function<void(const MatrixEventUserInfo&)> callback) {
+ auto range = users_by_room.equal_range(room);
+ for(auto &it = range.first; it != range.second; ++it) {
+ callback(it->second);
+ }
+ }
+
static void sort_room_body_items(std::vector<std::shared_ptr<BodyItem>> &room_body_items) {
std::sort(room_body_items.begin(), room_body_items.end(), [](const std::shared_ptr<BodyItem> &body_item1, const std::shared_ptr<BodyItem> &body_item2) {
RoomData *room1 = static_cast<RoomData*>(body_item1->userdata);
@@ -597,6 +641,10 @@ namespace QuickMedia {
return PluginResult::OK;
}
+ void MatrixRoomsPage::on_navigate_to_page(Body *body) {
+ body->items_set_dirty(true);
+ }
+
void MatrixRoomsPage::add_body_item(std::shared_ptr<BodyItem> body_item) {
insert_room_body_item_by_timestamp(body->items, body_item);
}
@@ -667,6 +715,10 @@ namespace QuickMedia {
return PluginResult::OK;
}
+ void MatrixRoomTagsPage::on_navigate_to_page(Body *body) {
+ body->items_set_dirty(true);
+ }
+
void MatrixRoomTagsPage::add_room_body_item_to_tag(std::shared_ptr<BodyItem> body_item, const std::string &tag) {
TagData *tag_data;
auto tag_body_it = tag_body_items_by_name.find(tag);
@@ -679,8 +731,8 @@ namespace QuickMedia {
tag_body_item->url = tag;
tag_body_items_by_name.insert(std::make_pair(tag, TagData{tag_body_item, {}}));
// TODO: Sort by tag priority
+ body->apply_search_filter_for_item(tag_body_item.get());
body->items.push_back(tag_body_item);
- body->items_set_dirty();
tag_data = &tag_body_items_by_name[tag];
tag_data->tag_item = tag_body_item;
}
@@ -783,8 +835,8 @@ namespace QuickMedia {
void MatrixInvitesPage::add_body_item(std::shared_ptr<BodyItem> body_item) {
// TODO: Insert in reverse order (to show the latest invite at the top?)
+ body->apply_search_filter_for_item(body_item.get());
body->insert_item_by_timestamp(std::move(body_item));
- body->items_set_dirty();
if(body->items.size() != prev_invite_count) {
prev_invite_count = body->items.size();
title = "Invites (" + std::to_string(body->items.size()) + ")";
@@ -812,6 +864,108 @@ namespace QuickMedia {
rooms_page->matrix_delegate->chat_page = nullptr;
}
+ // Returns |default_value| if the input items is empty
+ static size_t get_body_item_sorted_insert_position_by_author(BodyItems &body_items, const std::string &display_name, size_t default_value) {
+ for(size_t i = 0; i < body_items.size(); ++i) {
+ auto &body_item = body_items[i];
+ if(strcasecmp(display_name.c_str(), body_item->get_author().c_str()) <= 0)
+ return i;
+ }
+ return default_value;
+ }
+
+ static void add_user_to_body_by_user_info(Body *users_body, const MatrixEventUserInfo &user_info) {
+ std::string display_name = user_info.display_name.value_or(user_info.user_id);
+ size_t insert_index = get_body_item_sorted_insert_position_by_author(users_body->items, display_name, 0);
+
+ auto body_item = BodyItem::create("");
+ body_item->url = user_info.user_id;
+ body_item->set_author(std::move(display_name));
+ body_item->set_author_color(user_id_to_color(user_info.user_id));
+ body_item->set_description(user_info.user_id);
+ body_item->set_description_color(sf::Color(179, 179, 179));
+ if(user_info.avatar_url)
+ body_item->thumbnail_url = user_info.avatar_url.value();
+ body_item->thumbnail_mask_type = ThumbnailMaskType::CIRCLE;
+ body_item->thumbnail_size = sf::Vector2i(32, 32);
+
+ users_body->apply_search_filter_for_item(body_item.get());
+ users_body->items.insert(users_body->items.begin() + insert_index, std::move(body_item));
+ }
+
+ void MatrixChatPage::add_user(MatrixEventUserInfo user_info) {
+ if(!current_room || !users_body || user_info.room != current_room)
+ return;
+
+ // Ignore if the user already exists in the room
+ for(auto &body_item : users_body->items) {
+ if(body_item->url == user_info.user_id)
+ return;
+ }
+
+ add_user_to_body_by_user_info(users_body, user_info);
+ }
+
+ void MatrixChatPage::remove_user(MatrixEventUserInfo user_info) {
+ if(!current_room || !users_body || user_info.room != current_room)
+ return;
+
+ for(auto it = users_body->items.begin(), end = users_body->items.end(); it != end; ++it) {
+ if((*it)->url == user_info.user_id) {
+ users_body->items.erase(it);
+ return;
+ }
+ }
+ }
+
+ void MatrixChatPage::set_user_info(MatrixEventUserInfo user_info) {
+ if(!current_room || !users_body || user_info.room != current_room)
+ return;
+
+ for(auto it = users_body->items.begin(), end = users_body->items.end(); it != end; ++it) {
+ if((*it)->url == user_info.user_id) {
+ if(user_info.avatar_url)
+ (*it)->thumbnail_url = user_info.avatar_url.value();
+
+ if(user_info.display_name) {
+ std::string display_name;
+ if(user_info.display_name.value().empty())
+ display_name = user_info.user_id;
+ else
+ display_name = user_info.display_name.value();
+
+ (*it)->set_author(std::move(display_name));
+
+ auto user_body_item = *it;
+ users_body->items.erase(it);
+
+ // TODO: extract_first_line_remove_newline_elipses(room->get_user_display_name(message->user), AUTHOR_MAX_LENGTH),
+ // But that should be done in Text because we need author to be 100% the same as in the input to reorder users
+ users_body->apply_search_filter_for_item(user_body_item.get());
+ size_t insert_index = get_body_item_sorted_insert_position_by_author(users_body->items, user_body_item->get_author(), 0);
+ users_body->items.insert(users_body->items.begin() + insert_index, std::move(user_body_item));
+ }
+
+ return;
+ }
+ }
+ }
+
+ void MatrixChatPage::set_current_room(RoomData *room, Body *users_body) {
+ this->current_room = room;
+ this->users_body = users_body;
+ if(!room || !users_body)
+ return;
+
+ rooms_page->matrix_delegate->for_each_user_in_room(room, [users_body](const MatrixEventUserInfo &user_info) {
+ add_user_to_body_by_user_info(users_body, user_info);
+ });
+ }
+
+ size_t MatrixChatPage::get_num_users_in_current_room() const {
+ return users_body ? users_body->items.size() : 0;
+ }
+
PluginResult MatrixRoomDirectoryPage::submit(const std::string &title, const std::string&, std::vector<Tab> &result_tabs) {
std::string server_name = title;
@@ -1516,11 +1670,9 @@ namespace QuickMedia {
event_user_info.avatar_url = avatar_url;
if(is_new_user) {
- auto event = std::make_unique<MatrixAddUserEvent>(std::move(event_user_info));
- trigger_event(room_data, std::move(event));
+ trigger_event(room_data, MatrixEventType::ADD_USER, std::move(event_user_info));
} else {
- auto event = std::make_unique<MatrixUserInfoEvent>(std::move(event_user_info));
- trigger_event(room_data, std::move(event));
+ trigger_event(room_data, MatrixEventType::USER_INFO, std::move(event_user_info));
}
return user_info;
@@ -1779,8 +1931,7 @@ namespace QuickMedia {
if(is_new_user) {
MatrixEventUserInfo user_info;
user_info.user_id = user->user_id;
- auto event = std::make_unique<MatrixAddUserEvent>(std::move(user_info));
- trigger_event(room_data, std::move(event));
+ trigger_event(room_data, MatrixEventType::ADD_USER, std::move(user_info));
}
auto user_sender = user;
@@ -1791,8 +1942,7 @@ namespace QuickMedia {
if(is_new_user) {
MatrixEventUserInfo user_info;
user_info.user_id = user_sender->user_id;
- auto event = std::make_unique<MatrixAddUserEvent>(std::move(user_info));
- trigger_event(room_data, std::move(event));
+ trigger_event(room_data, MatrixEventType::ADD_USER, std::move(user_info));
}
}
@@ -1934,8 +2084,7 @@ namespace QuickMedia {
user_info.display_name = std::move(new_display_name);
user_info.avatar_url = std::move(new_avatar_url);
- auto event = std::make_unique<MatrixUserInfoEvent>(std::move(user_info));
- trigger_event(room_data, std::move(event));
+ trigger_event(room_data, MatrixEventType::USER_INFO, std::move(user_info));
}
} else {
body = user_display_name + " joined the room";
@@ -3781,7 +3930,7 @@ namespace QuickMedia {
if(room_it == room_data_by_id.end())
return;
- // We want to clear data instead of removing the object iself becasue we want to instance to still be valid,
+ // We want to clear data instead of removing the object iself because we want to instance to still be valid,
// also in the future we can have a "history" tag for rooms we have just left
rooms[room_it->second]->clear_data();
room_data_by_id.erase(room_it);
@@ -3898,11 +4047,9 @@ namespace QuickMedia {
user_info.avatar_url = avatar_url;
if(is_new_user) {
- auto event = std::make_unique<MatrixAddUserEvent>(std::move(user_info));
- trigger_event(room, std::move(event));
+ trigger_event(room, MatrixEventType::ADD_USER, std::move(user_info));
} else {
- auto event = std::make_unique<MatrixUserInfoEvent>(std::move(user_info));
- trigger_event(room, std::move(event));
+ trigger_event(room, MatrixEventType::USER_INFO, std::move(user_info));
}
}
#else
@@ -3974,19 +4121,6 @@ namespace QuickMedia {
#endif
}
- void Matrix::enable_event_queue(RoomData *room) {
- std::lock_guard<std::mutex> lock(event_queue_mutex);
- assert(!current_event_queue_room);
- current_event_queue_room = room;
- }
-
- void Matrix::disable_event_queue() {
- std::lock_guard<std::mutex> lock(event_queue_mutex);
- assert(current_event_queue_room);
- current_event_queue_room = nullptr;
- event_queue.clear();
- }
-
void Matrix::update() {
std::optional<std::function<void()>> task;
while((task = ui_thread_tasks.pop_if_available()) != std::nullopt) {
@@ -3994,20 +4128,27 @@ namespace QuickMedia {
}
}
- std::unique_ptr<MatrixEvent> Matrix::pop_event() {
- std::lock_guard<std::mutex> lock(event_queue_mutex);
- if(!current_event_queue_room || event_queue.empty())
- return nullptr;
-
- auto event_data = std::move(event_queue.front());
- event_queue.pop_front();
- return event_data;
- }
-
- void Matrix::trigger_event(RoomData *room, std::unique_ptr<MatrixEvent> event) {
- std::lock_guard<std::mutex> lock(event_queue_mutex);
- if(sync_is_cache || !current_event_queue_room || current_event_queue_room != room)
- return;
- event_queue.push_back(std::move(event));
+ void Matrix::trigger_event(RoomData *room, MatrixEventType type, MatrixEventUserInfo user_info) {
+ user_info.room = room;
+ switch(type) {
+ case MatrixEventType::ADD_USER: {
+ ui_thread_tasks.push([this, user_info{std::move(user_info)}]{
+ delegate->add_user(std::move(user_info));
+ });
+ break;
+ }
+ case MatrixEventType::REMOVE_USER: {
+ ui_thread_tasks.push([this, user_info{std::move(user_info)}]{
+ delegate->remove_user(std::move(user_info));
+ });
+ break;
+ }
+ case MatrixEventType::USER_INFO: {
+ ui_thread_tasks.push([this, user_info{std::move(user_info)}]{
+ delegate->set_user_info(std::move(user_info));
+ });
+ break;
+ }
+ }
}
} \ No newline at end of file