From 29c346fea61da23813dbee30f774547d913abf33 Mon Sep 17 00:00:00 2001 From: dec05eba Date: Wed, 30 Oct 2024 18:19:57 +0100 Subject: Only show kick/ban notification once --- TODO | 3 ++- include/Storage.hpp | 1 + plugins/Matrix.hpp | 11 +++++++++-- src/Storage.cpp | 15 +++++++++++++++ src/plugins/Matrix.cpp | 42 +++++++++++++++++++++++++++++++++++++----- 5 files changed, 64 insertions(+), 8 deletions(-) diff --git a/TODO b/TODO index 195e17b..0d7af13 100644 --- a/TODO +++ b/TODO @@ -297,4 +297,5 @@ v0.m3u8 doesn't work for some lbry videos (such as https://odysee.com/@MoneroMag Use DPMSInfoNotify. Use stb_image_resize2.h Youtube audio only download if audio stream not available, also for youtube-dl fallback. -Make history (local-manga and others) use relative path to the downloads directory for thumbnails. Otherwise the thumbnails wont show when moving the download directory. \ No newline at end of file +Make history (local-manga and others) use relative path to the downloads directory for thumbnails. Otherwise the thumbnails wont show when moving the download directory. +Keep the rooms that we were kicked/banned from so we can still read them and re-read the reason for why we were kicked/banned. Or add a list of historical rooms with leave reason. \ No newline at end of file diff --git a/include/Storage.hpp b/include/Storage.hpp index 60c15f6..86c34d2 100644 --- a/include/Storage.hpp +++ b/include/Storage.hpp @@ -34,6 +34,7 @@ namespace QuickMedia { bool file_get_last_modified_time_seconds(const char *path, time_t *result); int file_overwrite(const Path &path, const std::string &data); int file_overwrite_atomic(const Path &path, const std::string &data); + bool file_append(const Path &path, const std::string &data); // The callback is called with 0 as the argument (last_modified_seconds) void for_files_in_dir(const Path &path, FileIteratorCallback callback); void for_files_in_dir_sort_last_modified(const Path &path, FileIteratorCallback callback, FileSortDirection sort_dir = FileSortDirection::ASC); diff --git a/plugins/Matrix.hpp b/plugins/Matrix.hpp index a3ce633..23b0a8a 100644 --- a/plugins/Matrix.hpp +++ b/plugins/Matrix.hpp @@ -320,7 +320,7 @@ namespace QuickMedia { virtual ~MatrixDelegate() = default; virtual void join_room(RoomData *room) = 0; - virtual void leave_room(RoomData *room, LeaveType leave_type, const std::string &reason) = 0; + virtual void leave_room(RoomData *room, const std::string &event_id, LeaveType leave_type, const std::string &reason) = 0; // Note: calling |room| methods inside this function is not allowed virtual void room_add_tag(RoomData *room, const std::string &tag) = 0; @@ -356,7 +356,7 @@ namespace QuickMedia { MatrixQuickMedia(Program *program, Matrix *matrix, MatrixRoomsPage *rooms_page, MatrixRoomTagsPage *room_tags_page, MatrixInvitesPage *invites_page, MatrixNotificationsPage *notifications_page); void join_room(RoomData *room) override; - void leave_room(RoomData *room, LeaveType leave_type, const std::string &reason) override; + void leave_room(RoomData *room, const std::string &event_id, LeaveType leave_type, const std::string &reason) override; void room_add_tag(RoomData *room, const std::string &tag) override; void room_remove_tag(RoomData *room, const std::string &tag) override; void room_add_new_messages(RoomData *room, const Messages &messages, bool is_initial_sync, MessageDirection message_dir) override; @@ -759,6 +759,11 @@ namespace QuickMedia { MatrixDelegate* get_delegate(); + bool is_another_instance_running() const { return matrix_instance_already_running; } + + void mark_other_notification_as_read(const std::string &event_id); + bool is_other_notification_read(const std::string &event_id) const; + // Calls the |MatrixDelegate| pending events. // Should be called from the main (ui) thread void update(); @@ -783,6 +788,7 @@ namespace QuickMedia { void add_new_invites(); void parse_custom_emoji(const rapidjson::Value &custom_emoji_json); void load_custom_emoji_from_cache(); + void load_other_notifications(); PluginResult get_previous_room_messages(RoomData *room_data, bool latest_messages, size_t &num_new_messages, bool *reached_end = nullptr); void events_add_user_info(const rapidjson::Value &events_json, RoomData *room_data, int64_t timestamp); std::shared_ptr parse_user_info(const rapidjson::Value &json, const std::string &user_id, RoomData *room_data, int64_t timestamp); @@ -850,6 +856,7 @@ namespace QuickMedia { std::unordered_map custom_emoji_by_key; std::unordered_set silenced_invites; std::unordered_map qm_read_markers_by_room_cache; + std::unordered_set other_notifications_read; MessageQueue> decrypt_task; std::thread decrypt_thread; diff --git a/src/Storage.cpp b/src/Storage.cpp index 7bb3be6..5c12911 100644 --- a/src/Storage.cpp +++ b/src/Storage.cpp @@ -244,6 +244,21 @@ namespace QuickMedia { return rename_atomic(tmp_path.data.c_str(), path.data.c_str()); } + bool file_append(const Path &path, const std::string &data) { + FILE *file = fopen_eintr(path.data.c_str(), "ab"); + if(!file) { + perror(path.data.c_str()); + return false; + } + + if(fwrite_eintr(data.data(), data.size(), file) != data.size()) { + fclose(file); + return false; + } + + return fclose(file) == 0; + } + void for_files_in_dir(const Path &path, FileIteratorCallback callback) { try { for(auto &p : std::filesystem::directory_iterator(path.data)) { diff --git a/src/plugins/Matrix.cpp b/src/plugins/Matrix.cpp index 1b43b2d..7080bf9 100644 --- a/src/plugins/Matrix.cpp +++ b/src/plugins/Matrix.cpp @@ -629,12 +629,15 @@ namespace QuickMedia { rooms_page->add_body_item(body_item); } - void MatrixQuickMedia::leave_room(RoomData *room, LeaveType leave_type, const std::string &reason) { + void MatrixQuickMedia::leave_room(RoomData *room, const std::string &event_id, LeaveType leave_type, const std::string &reason) { room_body_item_by_room.erase(room); rooms_page->remove_body_item_by_room_id(room->id); room_tags_page->remove_body_item_by_room_id(room->id); - if(leave_type != LeaveType::LEAVE) + if(leave_type != LeaveType::LEAVE && (event_id.empty() || !matrix->is_other_notification_read(event_id))) { show_notification("QuickMedia", reason); + if(!event_id.empty()) + matrix->mark_other_notification_as_read(event_id); + } } void MatrixQuickMedia::room_add_tag(RoomData *room, const std::string &tag) { @@ -1674,6 +1677,7 @@ namespace QuickMedia { load_silenced_invites(); load_custom_emoji_from_cache(); + load_other_notifications(); sync_thread = std::thread([this, matrix_cache_dir]() { FILE *sync_cache_file; @@ -1858,8 +1862,8 @@ namespace QuickMedia { fwrite(json_data.data(), 1, json_data.size(), sync_cache_file); file_overwrite(get_cache_dir().join("matrix").join(update_cache_file_name), "1"); // To make sure the cache format is up to date - malloc_trim(0); } + malloc_trim(0); fclose(sync_cache_file); } } @@ -2208,6 +2212,18 @@ namespace QuickMedia { parse_custom_emoji(json_root); } + void Matrix::load_other_notifications() { + std::string result; + if(file_get_content(get_storage_dir().join("matrix").join("other_notifications_read"), result) != 0) + return; + + other_notifications_read.clear(); + string_split_view(result, '\n', [this](const char *str, size_t line) { + other_notifications_read.insert(std::string(str, line)); + return true; + }); + } + PluginResult Matrix::parse_sync_account_data(const rapidjson::Value &account_data_json) { if(!account_data_json.IsObject()) return PluginResult::OK; @@ -3884,6 +3900,10 @@ namespace QuickMedia { if(!type_json.IsString() || strcmp(type_json.GetString(), "m.room.member") != 0) continue; + const rapidjson::Value &event_id_json = GetMember(event_json, "event_id"); + if(!event_id_json.IsString()) + continue; + const rapidjson::Value &sender_json = GetMember(event_json, "sender"); if(!sender_json.IsString()) continue; @@ -3924,7 +3944,10 @@ namespace QuickMedia { if(!reason_str.empty()) desc += ", reason: " + reason_str; - ui_thread_tasks.push([this, room, leave_type, desc{std::move(desc)}]{ delegate->leave_room(room, leave_type, desc); }); + std::string event_id_str = event_id_json.GetString(); + ui_thread_tasks.push([this, room, event_id_str{std::move(event_id_str)}, leave_type, desc{std::move(desc)}]{ + delegate->leave_room(room, event_id_str, leave_type, desc); + }); remove_room(room_id_str); break; } @@ -4213,6 +4236,15 @@ namespace QuickMedia { return delegate; } + void Matrix::mark_other_notification_as_read(const std::string &event_id) { + other_notifications_read.insert(event_id); + file_append(get_storage_dir().join("matrix").join("other_notifications_read"), event_id + "\n"); + } + + bool Matrix::is_other_notification_read(const std::string &event_id) const { + return other_notifications_read.find(event_id) != other_notifications_read.end(); + } + PluginResult Matrix::post_message(RoomData *room, const std::string &body, std::string &event_id_response, const std::optional &file_info, const std::optional &thumbnail_info, const std::string &msgtype, const std::string &custom_transaction_id) { std::string transaction_id = custom_transaction_id; if(transaction_id.empty()) @@ -5629,7 +5661,7 @@ namespace QuickMedia { if(download_result == DownloadResult::OK) { RoomData *room = get_room_by_id(room_id); if(room) { - ui_thread_tasks.push([this, room]{ delegate->leave_room(room, LeaveType::LEAVE, ""); }); + ui_thread_tasks.push([this, room]{ delegate->leave_room(room, "", LeaveType::LEAVE, ""); }); remove_room(room_id); } } -- cgit v1.2.3