aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authordec05eba <dec05eba@protonmail.com>2020-10-01 11:03:30 +0200
committerdec05eba <dec05eba@protonmail.com>2020-10-01 11:03:30 +0200
commitcb60c5304db0b25d6ce2460fded4cd42a1dcf0dc (patch)
tree6889b66b45838063ccd662be251b1aa749a262ea /src
parentae02ed04389117d100070c47f3ae69abb9080231 (diff)
Matrix: show indication for unread messages and show the last message in the rooms list
Diffstat (limited to 'src')
-rw-r--r--src/QuickMedia.cpp81
-rw-r--r--src/plugins/Matrix.cpp25
2 files changed, 90 insertions, 16 deletions
diff --git a/src/QuickMedia.cpp b/src/QuickMedia.cpp
index cb58a27..15ae39c 100644
--- a/src/QuickMedia.cpp
+++ b/src/QuickMedia.cpp
@@ -3279,6 +3279,16 @@ namespace QuickMedia {
source.a + diff_a * progress);
}
+ static std::string extract_first_line(const std::string &str) {
+ size_t index = str.find('\n');
+ if(index == std::string::npos)
+ return str;
+ else if(index == 0)
+ return "";
+ else
+ return str.substr(0, index - 1);
+ }
+
void Program::chat_page() {
assert(current_plugin->name == "matrix");
Matrix *matrix = static_cast<Matrix*>(current_plugin);
@@ -3320,7 +3330,8 @@ namespace QuickMedia {
*/
// This is needed to get initial data, with joined rooms etc. TODO: Remove this once its cached
// and allow asynchronous update of rooms
- if(matrix->sync() != PluginResult::OK) {
+ RoomSyncMessages room_sync_messages;
+ if(matrix->sync(room_sync_messages) != PluginResult::OK) {
show_notification("QuickMedia", "Intial matrix sync failed", Urgency::CRITICAL);
current_page = Page::EXIT;
return;
@@ -3332,6 +3343,24 @@ namespace QuickMedia {
return;
}
+ struct RoomBodyData {
+ std::shared_ptr<BodyItem> body_item;
+ bool last_message_read;
+ };
+
+ std::unordered_map<std::string, RoomBodyData> body_items_by_room_id;
+ for(auto body_item : tabs[ROOMS_TAB_INDEX].body->items) {
+ // TODO: Set |last_message_read| depending on read markers (either remote matrix read markers or locally saved ones)
+ body_items_by_room_id[body_item->url] = { body_item, true };
+ }
+
+ for(auto &[room, messages] : room_sync_messages) {
+ auto room_body_item_it = body_items_by_room_id.find(room->id);
+ if(room_body_item_it != body_items_by_room_id.end() && !messages.empty()) {
+ room_body_item_it->second.body_item->set_description(matrix->message_get_author_displayname(room, messages.back().get()) + ": " + extract_first_line(messages.back()->body));
+ }
+ }
+
// TODO: the initial room to view should be the last viewed room when closing QuickMedia.
// The room id should be saved in a file when changing viewed room.
std::string current_room_id;
@@ -3341,6 +3370,11 @@ namespace QuickMedia {
// TODO: Allow empty initial room (if the user hasn't joined any room yet).
assert(!current_room_id.empty());
+ RoomBodyData *current_room_body_data = nullptr;
+ auto room_body_item_it = body_items_by_room_id.find(current_room_id);
+ if(room_body_item_it != body_items_by_room_id.end())
+ current_room_body_data = &room_body_item_it->second;
+
// get_all_room_messages is not needed here because its done in the loop, where the initial timeout is 0ms
enum class ChatState {
@@ -3423,7 +3457,12 @@ namespace QuickMedia {
return false;
};
- std::future<BodyItems> sync_future;
+ struct SyncFutureResult {
+ BodyItems body_items;
+ RoomSyncMessages room_sync_messages;
+ };
+
+ std::future<SyncFutureResult> sync_future;
bool sync_running = false;
std::string sync_future_room_id;
sf::Clock sync_timer;
@@ -3642,6 +3681,10 @@ namespace QuickMedia {
std::string err_msg = "Failed to get messages in room: " + current_room_id;
show_notification("QuickMedia", err_msg, Urgency::CRITICAL);
}
+
+ auto room_body_item_it = body_items_by_room_id.find(current_room_id);
+ if(room_body_item_it != body_items_by_room_id.end())
+ current_room_body_data = &room_body_item_it->second;
}
}
}
@@ -3757,30 +3800,38 @@ namespace QuickMedia {
sync_future = std::async(std::launch::async, [this, &sync_future_room_id]() {
Matrix *matrix = static_cast<Matrix*>(current_plugin);
- BodyItems result_items;
- if(matrix->sync() == PluginResult::OK) {
+ SyncFutureResult result;
+ if(matrix->sync(result.room_sync_messages) == PluginResult::OK) {
fprintf(stderr, "Synced matrix\n");
- if(matrix->get_new_room_messages(sync_future_room_id, result_items) != PluginResult::OK) {
+ if(matrix->get_new_room_messages(sync_future_room_id, result.body_items) != PluginResult::OK) {
fprintf(stderr, "Failed to get new matrix messages in room: %s\n", sync_future_room_id.c_str());
}
} else {
fprintf(stderr, "Failed to sync matrix\n");
}
- return result_items;
+ return result;
});
}
if(sync_future.valid() && sync_future.wait_for(std::chrono::seconds(0)) == std::future_status::ready) {
- BodyItems new_body_items = sync_future.get();
+ SyncFutureResult sync_result = sync_future.get();
// Ignore finished sync if it happened in another room. When we navigate back to the room we will get the messages again
if(sync_future_room_id == current_room_id) {
int num_items = tabs[MESSAGES_TAB_INDEX].body->items.size();
bool scroll_to_end = (num_items == 0 || (num_items > 0 && tabs[MESSAGES_TAB_INDEX].body->get_selected_item() == num_items - 1));
- tabs[MESSAGES_TAB_INDEX].body->append_items(std::move(new_body_items));
+ tabs[MESSAGES_TAB_INDEX].body->append_items(std::move(sync_result.body_items));
if(scroll_to_end)
tabs[MESSAGES_TAB_INDEX].body->select_last_item();
}
+ for(auto &[room, messages] : sync_result.room_sync_messages) {
+ auto room_body_item_it = body_items_by_room_id.find(room->id);
+ if(room_body_item_it != body_items_by_room_id.end() && !messages.empty()) {
+ room_body_item_it->second.body_item->set_description("Unread: " + matrix->message_get_author_displayname(room, messages.back().get()) + ": " + extract_first_line(messages.back()->body));
+ room_body_item_it->second.body_item->title_color = sf::Color(255, 100, 100);
+ room_body_item_it->second.last_message_read = false;
+ }
+ }
sync_running = false;
}
@@ -3872,8 +3923,18 @@ 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 && !tabs[selected_tab].body->is_last_item_fully_visible()) {
- window.draw(more_messages_below_rect);
+ if(tabs[selected_tab].type == ChatTabType::MESSAGES) {
+ if(tabs[selected_tab].body->is_last_item_fully_visible()) {
+ if(current_room_body_data && !current_room_body_data->last_message_read) {
+ if(strncmp(current_room_body_data->body_item->get_description().c_str(), "Unread: ", 8) == 0)
+ current_room_body_data->body_item->set_description(current_room_body_data->body_item->get_description().c_str() + 8);
+ // TODO: Show a line like nheko instead for unread messages, or something else
+ current_room_body_data->body_item->title_color = sf::Color::White;
+ current_room_body_data->last_message_read = true;
+ }
+ } else {
+ window.draw(more_messages_below_rect);
+ }
}
if(tabs[selected_tab].type == ChatTabType::MESSAGES) {
diff --git a/src/plugins/Matrix.cpp b/src/plugins/Matrix.cpp
index b5eb617..ed3b0af 100644
--- a/src/plugins/Matrix.cpp
+++ b/src/plugins/Matrix.cpp
@@ -34,7 +34,7 @@ namespace QuickMedia {
return PluginResult::OK;
}
- PluginResult Matrix::sync() {
+ PluginResult Matrix::sync(RoomSyncMessages &room_messages) {
std::vector<CommandArg> additional_args = {
{ "-H", "Authorization: Bearer " + access_token },
{ "-m", "35" }
@@ -73,7 +73,7 @@ namespace QuickMedia {
return PluginResult::ERR;
}
- PluginResult result = sync_response_to_body_items(json_root);
+ PluginResult result = sync_response_to_body_items(json_root, room_messages);
if(result != PluginResult::OK)
return result;
@@ -244,7 +244,7 @@ namespace QuickMedia {
return PluginResult::OK;
}
- PluginResult Matrix::sync_response_to_body_items(const Json::Value &root) {
+ PluginResult Matrix::sync_response_to_body_items(const Json::Value &root, RoomSyncMessages &room_messages) {
if(!root.isObject())
return PluginResult::ERR;
@@ -314,7 +314,7 @@ namespace QuickMedia {
const Json::Value &events_json = timeline_json["events"];
events_add_user_info(events_json, room_it->second.get());
- events_add_messages(events_json, room_it->second.get(), MessageDirection::AFTER);
+ events_add_messages(events_json, room_it->second.get(), MessageDirection::AFTER, &room_messages);
events_set_room_name(events_json, room_it->second.get());
}
@@ -400,10 +400,13 @@ namespace QuickMedia {
return "";
}
- void Matrix::events_add_messages(const Json::Value &events_json, RoomData *room_data, MessageDirection message_dir) {
+ void Matrix::events_add_messages(const Json::Value &events_json, RoomData *room_data, MessageDirection message_dir, RoomSyncMessages *room_messages) {
if(!events_json.isArray())
return;
+ std::vector<std::shared_ptr<Message>> *room_sync_messages = nullptr;
+ if(room_messages)
+ room_sync_messages = &(*room_messages)[room_data];
std::vector<std::shared_ptr<Message>> new_messages;
for(const Json::Value &event_item_json : events_json) {
@@ -484,6 +487,8 @@ namespace QuickMedia {
message->replaces_event_id = std::move(replaces_event_id);
new_messages.push_back(message);
room_data->message_by_event_id[event_id_str] = message;
+ if(room_sync_messages)
+ room_sync_messages->push_back(message);
}
// TODO: Loop and std::move instead? doesn't insert create copies?
@@ -626,7 +631,7 @@ namespace QuickMedia {
events_set_room_name(state_json, room_data);
const Json::Value &chunk_json = json_root["chunk"];
- events_add_messages(chunk_json, room_data, MessageDirection::BEFORE);
+ events_add_messages(chunk_json, room_data, MessageDirection::BEFORE, nullptr);
const Json::Value &end_json = json_root["end"];
if(!end_json.isString()) {
@@ -1431,4 +1436,12 @@ namespace QuickMedia {
Message *message_typed = (Message*)message;
return user_id == room_it->second->user_info[message_typed->user_id].user_id;
}
+
+ std::string Matrix::message_get_author_displayname(RoomData *room_data, Message *message) const {
+ if(message->user_id >= room_data->user_info.size()) {
+ fprintf(stderr, "Warning: no user with the index: %zu\n", message->user_id);
+ return "";
+ }
+ return room_data->user_info[message->user_id].display_name;
+ }
} \ No newline at end of file