aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Body.cpp14
-rw-r--r--src/QuickMedia.cpp118
-rw-r--r--src/plugins/Matrix.cpp231
3 files changed, 207 insertions, 156 deletions
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