aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordec05eba <dec05eba@protonmail.com>2020-10-22 21:56:33 +0200
committerdec05eba <dec05eba@protonmail.com>2020-10-22 21:56:33 +0200
commit97564d40636aafb251644f61a0b990e392afd7a4 (patch)
treed6cb19849445d4d2683024072f1966c7bb17c619
parent42ef59ef17cb0a56c6ac1d8f220db7ca461c5411 (diff)
Matrix: add pinned messages tab
-rw-r--r--include/Body.hpp1
-rw-r--r--plugins/Matrix.hpp22
-rw-r--r--src/Body.cpp46
-rw-r--r--src/QuickMedia.cpp221
-rw-r--r--src/Text.cpp7
-rw-r--r--src/plugins/Matrix.cpp66
6 files changed, 278 insertions, 85 deletions
diff --git a/include/Body.hpp b/include/Body.hpp
index baed595..5fde04e 100644
--- a/include/Body.hpp
+++ b/include/Body.hpp
@@ -34,6 +34,7 @@ namespace QuickMedia {
class BodyItem {
public:
BodyItem(std::string _title);
+ BodyItem& operator=(BodyItem &other);
static std::shared_ptr<BodyItem> create(std::string title) { return std::make_shared<BodyItem>(std::move(title)); }
diff --git a/plugins/Matrix.hpp b/plugins/Matrix.hpp
index f24a08f..c3c5539 100644
--- a/plugins/Matrix.hpp
+++ b/plugins/Matrix.hpp
@@ -78,6 +78,8 @@ namespace QuickMedia {
// Ignores duplicates
void append_messages(const std::vector<std::shared_ptr<Message>> &new_messages);
+ void append_pinned_events(std::vector<std::string> new_pinned_events);
+
std::shared_ptr<Message> get_message_by_id(const std::string &id);
std::vector<std::shared_ptr<UserInfo>> get_users_excluding_me(const std::string &my_user_id);
@@ -86,6 +88,7 @@ namespace QuickMedia {
void release_room_lock();
const std::vector<std::shared_ptr<Message>>& get_messages_thread_unsafe() const;
+ const std::vector<std::string>& get_pinned_events_unsafe() const;
std::string id;
std::string name;
@@ -111,6 +114,7 @@ namespace QuickMedia {
std::unordered_map<std::string, std::shared_ptr<UserInfo>> user_info_by_user_id;
std::vector<std::shared_ptr<Message>> messages;
std::unordered_map<std::string, std::shared_ptr<Message>> message_by_event_id;
+ std::vector<std::string> pinned_events;
};
enum class MessageDirection {
@@ -127,16 +131,23 @@ namespace QuickMedia {
};
using Messages = std::vector<std::shared_ptr<Message>>;
- using RoomSyncMessages = std::unordered_map<RoomData*, Messages>;
+
+ struct SyncData {
+ Messages messages;
+ std::vector<std::string> pinned_events;
+ };
+
+ using RoomSyncData = std::unordered_map<RoomData*, SyncData>;
using Rooms = std::vector<RoomData*>;
bool message_contains_user_mention(const std::string &msg, const std::string &username);
class Matrix {
public:
- PluginResult sync(RoomSyncMessages &room_messages);
+ PluginResult sync(RoomSyncData &room_sync_data);
void get_room_join_updates(Rooms &new_rooms);
- PluginResult get_all_synced_room_messages(RoomData *room, Messages &messages);
+ void get_all_synced_room_messages(RoomData *room, Messages &messages);
+ void get_all_pinned_events(RoomData *room, std::vector<std::string> &events);
PluginResult get_previous_room_messages(RoomData *room, Messages &messages);
// |url| should only be set when uploading media.
@@ -176,12 +187,13 @@ namespace QuickMedia {
bool use_tor = false;
private:
- PluginResult sync_response_to_body_items(const rapidjson::Document &root, RoomSyncMessages &room_messages);
+ PluginResult sync_response_to_body_items(const rapidjson::Document &root, RoomSyncData &room_sync_data);
PluginResult get_previous_room_messages(RoomData *room_data);
void events_add_user_info(const rapidjson::Value &events_json, RoomData *room_data);
void events_add_user_read_markers(const rapidjson::Value &events_json, RoomData *room_data);
- void events_add_messages(const rapidjson::Value &events_json, RoomData *room_data, MessageDirection message_dir, RoomSyncMessages *room_messages, bool has_unread_notifications);
+ void events_add_messages(const rapidjson::Value &events_json, RoomData *room_data, MessageDirection message_dir, RoomSyncData *room_sync_data, bool has_unread_notifications);
void events_set_room_name(const rapidjson::Value &events_json, RoomData *room_data);
+ void events_add_pinned_events(const rapidjson::Value &events_json, RoomData *room_data, RoomSyncData &room_sync_data);
std::shared_ptr<Message> parse_message_event(const rapidjson::Value &event_item_json, RoomData *room_data);
PluginResult upload_file(RoomData *room, const std::string &filepath, UploadInfo &file_info, UploadInfo &thumbnail_info, std::string &err_msg);
diff --git a/src/Body.cpp b/src/Body.cpp
index f1c101f..f9b3edc 100644
--- a/src/Body.cpp
+++ b/src/Body.cpp
@@ -35,6 +35,50 @@ namespace QuickMedia {
set_title(std::move(_title));
}
+ BodyItem& BodyItem::operator=(BodyItem &other) {
+ url = other.url;
+ thumbnail_url = other.thumbnail_url;
+ attached_content_url = other.attached_content_url;
+ visible = other.visible;
+ dirty = other.dirty;
+ dirty_description = other.dirty_description;
+ dirty_author = other.dirty_author;
+ dirty_timestamp = other.dirty_timestamp;
+ thumbnail_is_local = other.thumbnail_is_local;
+ if(other.title_text)
+ title_text = std::make_unique<Text>(*other.title_text);
+ else
+ title_text = nullptr;
+ if(other.description_text)
+ description_text = std::make_unique<Text>(*other.description_text);
+ else
+ description_text = nullptr;
+ if(other.author_text)
+ author_text = std::make_unique<Text>(*other.author_text);
+ else
+ author_text = nullptr;
+ if(other.timestamp_text)
+ timestamp_text = std::make_unique<sf::Text>(*other.timestamp_text);
+ else
+ timestamp_text = nullptr;
+ replies = other.replies;
+ post_number = other.post_number;
+ userdata = other.userdata;
+ last_drawn_time = other.last_drawn_time;
+ embedded_item_status = other.embedded_item_status;
+ embedded_item = other.embedded_item;
+ thumbnail_mask_type = other.thumbnail_mask_type;
+ thumbnail_size = other.thumbnail_size;
+ title = other.title;
+ description = other.description;
+ author = other.author;
+ timestamp = other.timestamp;
+ title_color = other.title_color;
+ author_color = other.author_color;
+ description_color = other.description_color;
+ return *this;
+ }
+
Body::Body(Program *program, sf::Font *font, sf::Font *bold_font, sf::Font *cjk_font, sf::Texture &loading_icon_texture) :
font(font),
bold_font(bold_font),
@@ -362,7 +406,7 @@ namespace QuickMedia {
float item_height = get_item_height(item.get());
prev_pos.y -= (item_height + spacing_y);
- if(prev_pos.y + item_height + spacing_y < start_y)
+ if(prev_pos.y + item_height + spacing_y <= start_y)
break;
// This is needed here rather than above the loop, since update_dirty_text cant be called inside scissor because it corrupts the text for some reason
diff --git a/src/QuickMedia.cpp b/src/QuickMedia.cpp
index d0a93fe..5c1bdfa 100644
--- a/src/QuickMedia.cpp
+++ b/src/QuickMedia.cpp
@@ -2856,13 +2856,7 @@ namespace QuickMedia {
}
}
- enum class ChatTabType {
- MESSAGES,
- ROOMS
- };
-
struct ChatTab {
- ChatTabType type;
std::unique_ptr<Body> body;
std::future<BodyItems> future;
sf::Text text;
@@ -2934,16 +2928,35 @@ namespace QuickMedia {
return result_items;
}
+ enum class PinnedEventStatus {
+ NONE,
+ LOADING,
+ FINISHED_LOADING,
+ FAILED_TO_LOAD
+ };
+
+ struct PinnedEventData {
+ std::string event_id;
+ PinnedEventStatus status = PinnedEventStatus::NONE;
+ };
+
void Program::chat_page() {
assert(strcmp(plugin_name, "matrix") == 0);
auto video_page = std::make_unique<MatrixVideoPage>(this);
std::vector<ChatTab> tabs;
- int selected_tab = 0;
+
+ ChatTab pinned_tab;
+ pinned_tab.body = std::make_unique<Body>(this, font.get(), bold_font.get(), cjk_font.get(), loading_icon);
+ pinned_tab.body->draw_thumbnails = true;
+ pinned_tab.body->thumbnail_max_size = CHAT_MESSAGE_THUMBNAIL_MAX_SIZE;
+ pinned_tab.body->thumbnail_mask_shader = &circle_mask_shader;
+ //pinned_tab.body->line_separator_color = sf::Color::Transparent;
+ pinned_tab.text = sf::Text("Pinned", *font, tab_text_size);
+ tabs.push_back(std::move(pinned_tab));
ChatTab messages_tab;
- messages_tab.type = ChatTabType::MESSAGES;
messages_tab.body = std::make_unique<Body>(this, font.get(), bold_font.get(), cjk_font.get(), loading_icon);
messages_tab.body->draw_thumbnails = true;
messages_tab.body->thumbnail_max_size = CHAT_MESSAGE_THUMBNAIL_MAX_SIZE;
@@ -2953,7 +2966,6 @@ namespace QuickMedia {
tabs.push_back(std::move(messages_tab));
ChatTab rooms_tab;
- rooms_tab.type = ChatTabType::ROOMS;
rooms_tab.body = std::make_unique<Body>(this, font.get(), bold_font.get(), cjk_font.get(), loading_icon);
rooms_tab.body->draw_thumbnails = true;
//rooms_tab.body->line_separator_color = sf::Color::Transparent;
@@ -2961,8 +2973,11 @@ namespace QuickMedia {
rooms_tab.text = sf::Text("Rooms", *font, tab_text_size);
tabs.push_back(std::move(rooms_tab));
- const int MESSAGES_TAB_INDEX = 0;
- const int ROOMS_TAB_INDEX = 1;
+ const int PINNED_TAB_INDEX = 0;
+ const int MESSAGES_TAB_INDEX = 1;
+ const int ROOMS_TAB_INDEX = 2;
+
+ int selected_tab = MESSAGES_TAB_INDEX;
// This is needed to get initial data, with joined rooms etc. TODO: Remove this once its cached
// and allow asynchronous update of rooms
@@ -2992,10 +3007,10 @@ namespace QuickMedia {
auto process_new_room_messages =
[this, &selected_tab, &current_room, &is_window_focused, &tabs, &find_top_body_position_for_unread_room, &find_top_body_position_for_mentioned_room]
- (RoomSyncMessages &room_sync_messages, bool is_first_sync) mutable
+ (RoomSyncData &room_sync_data, bool is_first_sync) mutable
{
- for(auto &[room, messages] : room_sync_messages) {
- for(auto &message : messages) {
+ for(auto &[room, sync_data] : room_sync_data) {
+ for(auto &message : sync_data.messages) {
if(message->mentions_me) {
room->has_unread_mention = true;
// TODO: What if the message or username begins with "-"? also make the notification image be the avatar of the user
@@ -3005,8 +3020,8 @@ namespace QuickMedia {
}
}
- for(auto &[room, messages] : room_sync_messages) {
- if(messages.empty())
+ for(auto &[room, sync_data] : room_sync_data) {
+ if(sync_data.messages.empty())
continue;
std::shared_ptr<UserInfo> me = matrix->get_me(room);
@@ -3020,7 +3035,7 @@ namespace QuickMedia {
// TODO: this wont always work because we dont display all types of messages from server, such as "joined", "left", "kicked", "banned", "changed avatar", "changed display name", etc.
// TODO: Binary search?
Message *last_unread_message = nullptr;
- for(auto &message : messages) {
+ for(auto &message : sync_data.messages) {
if(message->related_event_type != RelatedEventType::EDIT && message->related_event_type != RelatedEventType::REDACTION && message->timestamp > read_marker_message_timestamp)
last_unread_message = message.get();
}
@@ -3060,7 +3075,7 @@ namespace QuickMedia {
}
} else if(is_first_sync) {
Message *last_unread_message = nullptr;
- for(auto it = messages.rbegin(), end = messages.rend(); it != end; ++it) {
+ for(auto it = sync_data.messages.rbegin(), end = sync_data.messages.rend(); it != end; ++it) {
if((*it)->related_event_type != RelatedEventType::EDIT && (*it)->related_event_type != RelatedEventType::REDACTION) {
last_unread_message = (*it).get();
break;
@@ -3170,6 +3185,19 @@ namespace QuickMedia {
}
};
+ auto process_new_pinned_events = [&tabs](const std::vector<std::string> &pinned_events) {
+ // TODO: Add message to rooms messages when there are new pinned events
+ for(const std::string &event : pinned_events) {
+ auto body = BodyItem::create("");
+ body->set_description("Loading message...");
+ PinnedEventData *event_data = new PinnedEventData();
+ event_data->event_id = event;
+ event_data->status = PinnedEventStatus::NONE;
+ body->userdata = event_data;
+ tabs[PINNED_TAB_INDEX].body->items.push_back(std::move(body));
+ }
+ };
+
SearchBar room_search_bar(*font, &plugin_logo, "Search...");
room_search_bar.autocomplete_search_delay = SEARCH_DELAY_FILTER;
room_search_bar.onTextUpdateCallback = [&tabs](const std::string &text) {
@@ -3179,7 +3207,7 @@ namespace QuickMedia {
room_search_bar.onTextSubmitCallback =
[this, &tabs, &selected_tab, &current_room, &room_name_text,
- &modify_related_messages_in_current_room, &room_avatar_thumbnail_data,
+ &modify_related_messages_in_current_room, &process_new_pinned_events, &room_avatar_thumbnail_data,
&read_marker_timeout_ms, &redraw, &room_search_bar]
(const std::string&)
{
@@ -3194,15 +3222,20 @@ namespace QuickMedia {
selected_tab = MESSAGES_TAB_INDEX;
tabs[MESSAGES_TAB_INDEX].body->clear_items();
- Messages new_messages;
- if(matrix->get_all_synced_room_messages(current_room, new_messages) == PluginResult::OK) {
- tabs[MESSAGES_TAB_INDEX].body->insert_items_by_timestamps(messages_to_body_items(new_messages, matrix->get_me(current_room).get()));
- modify_related_messages_in_current_room(new_messages);
- tabs[MESSAGES_TAB_INDEX].body->select_last_item();
- } else {
- std::string err_msg = "Failed to get messages in room: " + current_room->id;
- show_notification("QuickMedia", err_msg, Urgency::CRITICAL);
+ for(auto &body_item : tabs[PINNED_TAB_INDEX].body->items) {
+ delete((PinnedEventData*)body_item->userdata);
}
+ tabs[PINNED_TAB_INDEX].body->clear_items();
+
+ Messages all_messages;
+ matrix->get_all_synced_room_messages(current_room, all_messages);
+ tabs[MESSAGES_TAB_INDEX].body->insert_items_by_timestamps(messages_to_body_items(all_messages, matrix->get_me(current_room).get()));
+ modify_related_messages_in_current_room(all_messages);
+ tabs[MESSAGES_TAB_INDEX].body->select_last_item();
+
+ std::vector<std::string> pinned_events;
+ matrix->get_all_pinned_events(current_room, pinned_events);
+ process_new_pinned_events(pinned_events);
room_name_text.setString(static_cast<BodyItem*>(current_room->userdata)->get_title());
room_avatar_thumbnail_data = std::make_shared<ThumbnailData>();
@@ -3217,11 +3250,11 @@ namespace QuickMedia {
chat_input.draw_background = false;
chat_input.set_editable(false);
- chat_input.on_submit_callback = [this, &chat_input, &tabs, &selected_tab, &current_room, &new_page, &chat_state, &currently_operating_on_item](const std::string &text) mutable {
+ chat_input.on_submit_callback = [this, &chat_input, &selected_tab, &current_room, &new_page, &chat_state, &currently_operating_on_item](const std::string &text) mutable {
if(!current_room)
return false;
- if(tabs[selected_tab].type == ChatTabType::MESSAGES) {
+ if(selected_tab == MESSAGES_TAB_INDEX) {
if(text.empty())
return false;
@@ -3282,7 +3315,7 @@ namespace QuickMedia {
struct SyncFutureResult {
Rooms rooms;
- RoomSyncMessages room_sync_messages;
+ RoomSyncData room_sync_data;
};
std::future<SyncFutureResult> sync_future;
@@ -3294,18 +3327,52 @@ namespace QuickMedia {
bool fetching_previous_messages_running = false;
RoomData *previous_messages_future_room = nullptr;
- std::future<std::shared_ptr<Message>> fetch_reply_message_future;
- bool fetching_reply_message_running = false;
- RoomData *fetch_reply_future_room = nullptr;
- BodyItem *fetch_reply_body_item = nullptr;
+ //const int num_fetch_message_threads = 4;
+ std::future<std::shared_ptr<Message>> fetch_message_future;
+ bool fetching_message_running = false;
+ RoomData *fetch_future_room = nullptr;
+ BodyItem *fetch_body_item = nullptr;
+ int fetch_message_tab = -1;
// TODO: How about instead fetching all messages we have, not only the visible ones? also fetch with multiple threads.
// TODO: Cancel when going to another room?
- tabs[MESSAGES_TAB_INDEX].body->body_item_render_callback = [this, &current_room, &fetch_reply_message_future, &tabs, &find_body_item_by_event_id, &fetching_reply_message_running, &fetch_reply_future_room, &fetch_reply_body_item](BodyItem *body_item) {
- if(fetching_reply_message_running || !current_room)
+ tabs[PINNED_TAB_INDEX].body->body_item_render_callback = [this, &current_room, &fetch_message_future, &tabs, &find_body_item_by_event_id, &fetching_message_running, &fetch_future_room, &fetch_body_item, &fetch_message_tab](BodyItem *body_item) {
+ if(fetching_message_running || !current_room)
+ return;
+
+ PinnedEventData *event_data = static_cast<PinnedEventData*>(body_item->userdata);
+ if(!event_data || event_data->status != PinnedEventStatus::NONE)
+ return;
+
+ // Check if we already have the referenced message as a body item in the messages list, so we dont create a new one
+ auto related_body_item = find_body_item_by_event_id(tabs[MESSAGES_TAB_INDEX].body->items.data(), tabs[MESSAGES_TAB_INDEX].body->items.size(), event_data->event_id);
+ if(related_body_item) {
+ *body_item = *related_body_item;
+ event_data->status = PinnedEventStatus::FINISHED_LOADING;
+ body_item->userdata = event_data;
+ return;
+ }
+
+ fetching_message_running = true;
+ std::string message_event_id = event_data->event_id;
+ fetch_future_room = current_room;
+ fetch_body_item = body_item;
+ body_item->embedded_item_status = EmbeddedItemStatus::LOADING;
+ fetch_message_tab = PINNED_TAB_INDEX;
+ // TODO: Check if the message is already cached before calling async? is this needed? is async creation expensive?
+ fetch_message_future = std::async(std::launch::async, [this, &fetch_future_room, message_event_id]() {
+ return matrix->get_message_by_id(fetch_future_room, message_event_id);
+ });
+ };
+
+ // TODO: How about instead fetching all messages we have, not only the visible ones? also fetch with multiple threads.
+ // TODO: Cancel when going to another room?
+ tabs[MESSAGES_TAB_INDEX].body->body_item_render_callback = [this, &current_room, &fetch_message_future, &tabs, &find_body_item_by_event_id, &fetching_message_running, &fetch_future_room, &fetch_body_item, &fetch_message_tab](BodyItem *body_item) {
+ if(fetching_message_running || !current_room)
return;
Message *message = static_cast<Message*>(body_item->userdata);
+ assert(message);
if(message->related_event_id.empty() || body_item->embedded_item_status != EmbeddedItemStatus::NONE)
return;
@@ -3317,14 +3384,15 @@ namespace QuickMedia {
return;
}
- fetching_reply_message_running = true;
+ fetching_message_running = true;
std::string message_event_id = message->related_event_id;
- fetch_reply_future_room = current_room;
- fetch_reply_body_item = body_item;
+ fetch_future_room = current_room;
+ fetch_body_item = body_item;
body_item->embedded_item_status = EmbeddedItemStatus::LOADING;
+ fetch_message_tab = MESSAGES_TAB_INDEX;
// TODO: Check if the message is already cached before calling async? is this needed? is async creation expensive?
- fetch_reply_message_future = std::async(std::launch::async, [this, &fetch_reply_future_room, message_event_id]() {
- return matrix->get_message_by_id(fetch_reply_future_room, message_event_id);
+ fetch_message_future = std::async(std::launch::async, [this, &fetch_future_room, message_event_id]() {
+ return matrix->get_message_by_id(fetch_future_room, message_event_id);
});
};
@@ -3403,10 +3471,10 @@ namespace QuickMedia {
}
};
- auto add_new_messages_to_current_room = [this, &tabs, &selected_tab, &current_room, &is_window_focused](Messages &messages) {
+ auto add_new_messages_to_current_room = [this, &tabs, &selected_tab, &current_room](Messages &messages) {
int num_items = tabs[MESSAGES_TAB_INDEX].body->items.size();
bool scroll_to_end = num_items == 0;
- if(tabs[MESSAGES_TAB_INDEX].body->is_selected_item_last_visible_item() && selected_tab == MESSAGES_TAB_INDEX && is_window_focused)
+ if(tabs[MESSAGES_TAB_INDEX].body->is_selected_item_last_visible_item() && selected_tab == MESSAGES_TAB_INDEX)
scroll_to_end = true;
BodyItem *selected_item = tabs[MESSAGES_TAB_INDEX].body->get_selected();
@@ -3456,7 +3524,7 @@ namespace QuickMedia {
while (window.pollEvent(event)) {
base_event_handler(event, PageType::EXIT, tabs[selected_tab].body.get(), nullptr, false, false);
- if(tabs[selected_tab].type == ChatTabType::ROOMS) {
+ if(selected_tab == ROOMS_TAB_INDEX) {
if(event.type == sf::Event::TextEntered)
room_search_bar.onTextEntered(event.text.unicode);
room_search_bar.on_event(event);
@@ -3487,7 +3555,7 @@ namespace QuickMedia {
hit_top = false;
break;
}
- if(hit_top && !fetching_previous_messages_running && tabs[selected_tab].type == ChatTabType::MESSAGES && current_room) {
+ if(hit_top && !fetching_previous_messages_running && selected_tab == MESSAGES_TAB_INDEX && current_room) {
gradient_inc = 0;
fetching_previous_messages_running = true;
previous_messages_future_room = current_room;
@@ -3526,7 +3594,7 @@ namespace QuickMedia {
}
}
- if(tabs[selected_tab].type == ChatTabType::MESSAGES && event.key.code == sf::Keyboard::Enter) {
+ if(selected_tab == MESSAGES_TAB_INDEX && event.key.code == sf::Keyboard::Enter) {
BodyItem *selected = tabs[selected_tab].body->get_selected();
if(selected) {
MessageType message_type = static_cast<Message*>(selected->userdata)->type;
@@ -3603,7 +3671,7 @@ namespace QuickMedia {
continue;
launch_url(selected_item->get_title());
}
- } else if(event.type == sf::Event::KeyReleased && chat_state == ChatState::NAVIGATING && tabs[selected_tab].type == ChatTabType::MESSAGES && current_room) {
+ } else if(event.type == sf::Event::KeyReleased && chat_state == ChatState::NAVIGATING && selected_tab == MESSAGES_TAB_INDEX && current_room) {
if(event.key.code == sf::Keyboard::U) {
new_page = PageType::FILE_MANAGER;
chat_input.set_editable(false);
@@ -3676,7 +3744,7 @@ namespace QuickMedia {
}
}
- if((chat_state == ChatState::TYPING_MESSAGE || chat_state == ChatState::REPLYING || chat_state == ChatState::EDITING) && tabs[selected_tab].type == ChatTabType::MESSAGES) {
+ if((chat_state == ChatState::TYPING_MESSAGE || chat_state == ChatState::REPLYING || chat_state == ChatState::EDITING) && selected_tab == MESSAGES_TAB_INDEX) {
if(event.type == sf::Event::TextEntered) {
//chat_input.onTextEntered(event.text.unicode);
// TODO: Also show typing event when ctrl+v pasting?
@@ -3825,6 +3893,8 @@ namespace QuickMedia {
room_name_padding_y = room_search_bar.getBottomWithoutShadow();
tab_vertical_offset = 0.0f;
padding_bottom = 10.0f;
+ } else if(selected_tab == PINNED_TAB_INDEX) {
+ padding_bottom = 10.0f;
}
tab_shade_height = tab_spacer_height + std::floor(tab_vertical_offset) + tab_height + room_name_padding_y + padding_bottom;
@@ -3861,7 +3931,7 @@ namespace QuickMedia {
sync_timer.restart();
sync_future = std::async(std::launch::async, [this]() {
SyncFutureResult result;
- if(matrix->sync(result.room_sync_messages) == PluginResult::OK) {
+ if(matrix->sync(result.room_sync_data) == PluginResult::OK) {
fprintf(stderr, "Synced matrix\n");
matrix->get_room_join_updates(result.rooms);
} else {
@@ -3877,13 +3947,14 @@ namespace QuickMedia {
add_new_rooms(sync_result.rooms);
- auto room_messages_it = sync_result.room_sync_messages.find(current_room);
- if(room_messages_it != sync_result.room_sync_messages.end()) {
- add_new_messages_to_current_room(room_messages_it->second);
- modify_related_messages_in_current_room(room_messages_it->second);
+ auto room_messages_it = sync_result.room_sync_data.find(current_room);
+ if(room_messages_it != sync_result.room_sync_data.end()) {
+ add_new_messages_to_current_room(room_messages_it->second.messages);
+ modify_related_messages_in_current_room(room_messages_it->second.messages);
+ process_new_pinned_events(room_messages_it->second.pinned_events);
}
- process_new_room_messages(sync_result.room_sync_messages, !synced);
+ process_new_room_messages(sync_result.room_sync_data, !synced);
sync_running = false;
synced = true;
}
@@ -3915,19 +3986,31 @@ namespace QuickMedia {
fetching_previous_messages_running = false;
}
- if(fetching_reply_message_running && fetch_reply_message_future.valid() && fetch_reply_message_future.wait_for(std::chrono::seconds(0)) == std::future_status::ready) {
- std::shared_ptr<Message> replied_to_message = fetch_reply_message_future.get();
- fprintf(stderr, "Finished fetching reply to message: %s\n", replied_to_message ? replied_to_message->event_id.c_str() : "(null)");
+ if(fetching_message_running && fetch_message_future.valid() && fetch_message_future.wait_for(std::chrono::seconds(0)) == std::future_status::ready) {
+ std::shared_ptr<Message> message = fetch_message_future.get();
+ fprintf(stderr, "Finished fetching message: %s\n", message ? message->event_id.c_str() : "(null)");
// Ignore finished fetch of messages if it happened in another room. When we navigate back to the room we will get the messages again
- if(fetch_reply_future_room == current_room) {
- if(replied_to_message) {
- fetch_reply_body_item->embedded_item = message_to_body_item(replied_to_message.get(), matrix->get_me(current_room).get());
- fetch_reply_body_item->embedded_item_status = EmbeddedItemStatus::FINISHED_LOADING;
- } else {
- fetch_reply_body_item->embedded_item_status = EmbeddedItemStatus::FAILED_TO_LOAD;
+ if(fetch_future_room == current_room) {
+ if(fetch_message_tab == PINNED_TAB_INDEX) {
+ PinnedEventData *event_data = static_cast<PinnedEventData*>(fetch_body_item->userdata);
+ if(message) {
+ *fetch_body_item = *message_to_body_item(message.get(), matrix->get_me(current_room).get());
+ event_data->status = PinnedEventStatus::FINISHED_LOADING;
+ fetch_body_item->userdata = event_data;
+ } else {
+ event_data->status = PinnedEventStatus::FAILED_TO_LOAD;
+ }
+ } else if(fetch_message_tab == MESSAGES_TAB_INDEX) {
+ if(message) {
+ fetch_body_item->embedded_item = message_to_body_item(message.get(), matrix->get_me(current_room).get());
+ fetch_body_item->embedded_item_status = EmbeddedItemStatus::FINISHED_LOADING;
+ } else {
+ fetch_body_item->embedded_item_status = EmbeddedItemStatus::FAILED_TO_LOAD;
+ }
}
}
- fetching_reply_message_running = false;
+ fetching_message_running = false;
+ fetch_message_tab = -1;
}
//chat_input.update();
@@ -3946,7 +4029,7 @@ namespace QuickMedia {
tab_shade.setSize(sf::Vector2f(window_size.x, tab_shade_height));
window.draw(tab_shade);
- if(tabs[selected_tab].type == ChatTabType::MESSAGES) {
+ if(selected_tab == MESSAGES_TAB_INDEX) {
float room_name_text_offset_x = 0.0f;
if(room_avatar_sprite.getTexture() && room_avatar_sprite.getTexture()->getNativeHandle() != 0) {
auto room_avatar_texture_size = room_avatar_sprite.getTexture()->getSize();
@@ -3958,7 +4041,7 @@ namespace QuickMedia {
}
room_name_text.setPosition(body_pos.x + room_name_text_offset_x, room_name_text_padding_y + 4.0f);
window.draw(room_name_text);
- } else if(tabs[selected_tab].type == ChatTabType::ROOMS) {
+ } else if(selected_tab == ROOMS_TAB_INDEX) {
room_search_bar.draw(window, false);
}
@@ -3987,7 +4070,7 @@ namespace QuickMedia {
}
// TODO: Have one for each room. Also add bottom one? for fetching new messages (currently not implemented, is it needed?)
- if(fetching_previous_messages_running && tabs[selected_tab].type == ChatTabType::MESSAGES) {
+ if(fetching_previous_messages_running && selected_tab == MESSAGES_TAB_INDEX) {
double progress = 0.5 + std::sin(std::fmod(gradient_inc, 360.0) * 0.017453292519943295 - 1.5707963267948966*0.5) * 0.5;
gradient_inc += (frame_time_ms * 0.5);
sf::Color top_color = interpolate_colors(back_color, sf::Color(175, 180, 188), progress);
@@ -4024,7 +4107,7 @@ namespace QuickMedia {
tabs[MESSAGES_TAB_INDEX].body->draw_item(window, currently_operating_on_item.get(), body_item_pos, body_item_size);
}
- if(tabs[selected_tab].type == ChatTabType::MESSAGES && current_room && current_room->userdata && !current_room->last_message_read) {
+ if(selected_tab == MESSAGES_TAB_INDEX && current_room && current_room->userdata && !current_room->last_message_read) {
if(tabs[selected_tab].body->is_last_item_fully_visible()) {
BodyItem *current_room_body_item = static_cast<BodyItem*>(current_room->userdata);
std::string room_desc = current_room_body_item->get_description();
@@ -4050,7 +4133,7 @@ namespace QuickMedia {
window.draw(loading_text);
}
- if(tabs[selected_tab].type == ChatTabType::MESSAGES && current_room) {
+ if(selected_tab == MESSAGES_TAB_INDEX && current_room) {
BodyItem *last_visible_item = tabs[selected_tab].body->get_last_fully_visible_item();
if(is_window_focused && chat_state != ChatState::URL_SELECTION && current_room && last_visible_item && !setting_read_marker && read_marker_timer.getElapsedTime().asMilliseconds() >= read_marker_timeout_ms) {
Message *message = (Message*)last_visible_item->userdata;
diff --git a/src/Text.cpp b/src/Text.cpp
index 44730c3..51ff054 100644
--- a/src/Text.cpp
+++ b/src/Text.cpp
@@ -161,6 +161,10 @@ namespace QuickMedia
{
this->editable = editable;
dirtyCaret = true;
+ if(editable)
+ dirty = true;
+ else
+ vertices_linear.clear();
}
}
@@ -466,7 +470,8 @@ namespace QuickMedia
}
boundingBox.height = num_lines * line_height;
- // TODO: Clear vertices_linear when not in edit mode, but take into consideration switching between edit/not-edit mode
+ if(!editable)
+ vertices_linear.clear();
}
void Text::updateCaret()
diff --git a/src/plugins/Matrix.cpp b/src/plugins/Matrix.cpp
index b6f6f76..9a2f70b 100644
--- a/src/plugins/Matrix.cpp
+++ b/src/plugins/Matrix.cpp
@@ -75,6 +75,11 @@ namespace QuickMedia {
}
}
+ void RoomData::append_pinned_events(std::vector<std::string> new_pinned_events) {
+ std::lock_guard<std::mutex> lock(room_mutex);
+ pinned_events.insert(pinned_events.end(), new_pinned_events.begin(), new_pinned_events.end());
+ }
+
std::shared_ptr<Message> RoomData::get_message_by_id(const std::string &id) {
std::lock_guard<std::mutex> lock(room_mutex);
auto message_it = message_by_event_id.find(id);
@@ -106,7 +111,11 @@ namespace QuickMedia {
return messages;
}
- PluginResult Matrix::sync(RoomSyncMessages &room_messages) {
+ const std::vector<std::string>& RoomData::get_pinned_events_unsafe() const {
+ return pinned_events;
+ }
+
+ PluginResult Matrix::sync(RoomSyncData &room_sync_data) {
std::vector<CommandArg> additional_args = {
{ "-H", "Authorization: Bearer " + access_token },
{ "-m", "35" }
@@ -122,7 +131,7 @@ namespace QuickMedia {
DownloadResult download_result = download_json(json_root, url, std::move(additional_args), true);
if(download_result != DownloadResult::OK) return download_result_to_plugin_result(download_result);
- PluginResult result = sync_response_to_body_items(json_root, room_messages);
+ PluginResult result = sync_response_to_body_items(json_root, room_sync_data);
if(result != PluginResult::OK)
return result;
@@ -148,11 +157,16 @@ namespace QuickMedia {
room_list_read_index += num_new_rooms;
}
- PluginResult Matrix::get_all_synced_room_messages(RoomData *room, Messages &messages) {
+ void Matrix::get_all_synced_room_messages(RoomData *room, Messages &messages) {
room->acquire_room_lock();
messages = room->get_messages_thread_unsafe();
room->release_room_lock();
- return PluginResult::OK;
+ }
+
+ void Matrix::get_all_pinned_events(RoomData *room, std::vector<std::string> &events) {
+ room->acquire_room_lock();
+ events = room->get_pinned_events_unsafe();
+ room->release_room_lock();
}
PluginResult Matrix::get_previous_room_messages(RoomData *room, Messages &messages) {
@@ -171,7 +185,7 @@ namespace QuickMedia {
return PluginResult::OK;
}
- PluginResult Matrix::sync_response_to_body_items(const rapidjson::Document &root, RoomSyncMessages &room_messages) {
+ PluginResult Matrix::sync_response_to_body_items(const rapidjson::Document &root, RoomSyncData &room_sync_data) {
if(!root.IsObject())
return PluginResult::ERR;
@@ -206,6 +220,7 @@ namespace QuickMedia {
const rapidjson::Value &events_json = GetMember(state_json, "events");
events_add_user_info(events_json, room);
events_set_room_name(events_json, room);
+ events_add_pinned_events(events_json, room, room_sync_data);
}
const rapidjson::Value &ephemeral_json = GetMember(it.value, "ephemeral");
@@ -236,7 +251,7 @@ namespace QuickMedia {
const rapidjson::Value &events_json = GetMember(ephemeral_json, "events");
events_add_user_read_markers(events_json, room);
}
- events_add_messages(events_json, room, MessageDirection::AFTER, &room_messages, has_unread_notifications);
+ events_add_messages(events_json, room, MessageDirection::AFTER, &room_sync_data, has_unread_notifications);
} else {
if(ephemeral_json.IsObject()) {
const rapidjson::Value &events_json = GetMember(ephemeral_json, "events");
@@ -454,7 +469,7 @@ namespace QuickMedia {
return false;
}
- void Matrix::events_add_messages(const rapidjson::Value &events_json, RoomData *room_data, MessageDirection message_dir, RoomSyncMessages *room_messages, bool has_unread_notifications) {
+ void Matrix::events_add_messages(const rapidjson::Value &events_json, RoomData *room_data, MessageDirection message_dir, RoomSyncData *room_sync_data, bool has_unread_notifications) {
if(!events_json.IsArray())
return;
@@ -471,8 +486,8 @@ namespace QuickMedia {
return;
// TODO: Add directly to this instead when set? otherwise add to new_messages
- if(room_messages)
- (*room_messages)[room_data] = new_messages;
+ if(room_sync_data)
+ (*room_sync_data)[room_data].messages = new_messages;
// TODO: Loop and std::move instead? doesn't insert create copies?
if(message_dir == MessageDirection::BEFORE) {
@@ -753,6 +768,39 @@ namespace QuickMedia {
}
}
+ void Matrix::events_add_pinned_events(const rapidjson::Value &events_json, RoomData *room_data, RoomSyncData &room_sync_data) {
+ if(!events_json.IsArray())
+ return;
+
+ std::vector<std::string> pinned_events;
+ for(const rapidjson::Value &event_item_json : events_json.GetArray()) {
+ if(!event_item_json.IsObject())
+ continue;
+
+ const rapidjson::Value &type_json = GetMember(event_item_json, "type");
+ if(!type_json.IsString() || strcmp(type_json.GetString(), "m.room.pinned_events") != 0)
+ continue;
+
+ const rapidjson::Value &content_json = GetMember(event_item_json, "content");
+ if(!content_json.IsObject())
+ continue;
+
+ const rapidjson::Value &pinned_json = GetMember(content_json, "pinned");
+ if(!pinned_json.IsArray())
+ continue;
+
+ for(const rapidjson::Value &pinned_item_json : pinned_json.GetArray()) {
+ if(!pinned_item_json.IsString())
+ continue;
+
+ pinned_events.push_back(std::string(pinned_item_json.GetString(), pinned_item_json.GetStringLength()));
+ }
+ }
+
+ room_sync_data[room_data].pinned_events = pinned_events;
+ room_data->append_pinned_events(std::move(pinned_events));
+ }
+
PluginResult Matrix::get_previous_room_messages(RoomData *room_data) {
std::string from = room_data->prev_batch;
if(from.empty()) {