From 6775a64ed5534bfa151de282bb41ec0c6ab7cff7 Mon Sep 17 00:00:00 2001 From: csoler Date: Mon, 15 May 2023 21:54:27 +0200 Subject: [PATCH] factored the collection of latest channel post versions and added a proper counting for new/unread posts --- .../src/gui/gxschannels/GxsChannelDialog.cpp | 20 +- .../gui/gxschannels/GxsChannelPostsModel.cpp | 265 +----------------- 2 files changed, 21 insertions(+), 264 deletions(-) diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelDialog.cpp b/retroshare-gui/src/gui/gxschannels/GxsChannelDialog.cpp index 6d28f97a8..47317c801 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelDialog.cpp +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelDialog.cpp @@ -369,7 +369,25 @@ void GxsChannelDialog::toggleAutoDownload() bool GxsChannelDialog::getGroupStatistics(const RsGxsGroupId& groupId,GxsGroupStatistic& stat) { - return rsGxsChannels->getChannelStatistics(groupId,stat); + // What follows is a hack to replace the GXS group statistics by the actual count of unread messages in channels, + // which should take into account old post versions, discard comments and votes, etc. + + RsGxsChannelStatistics s; + bool res = rsGxsChannels->getChannelStatistics(groupId,s); + + if(!res) + return false; + + stat.mGrpId = groupId; + stat.mNumMsgs = s.mNumberOfPosts; + + stat.mTotalSizeOfMsgs = 0; // hopefuly unused. Required the loading of the full channel data, so not very convenient. + stat.mNumThreadMsgsNew = s.mNumberOfNewPosts; + stat.mNumThreadMsgsUnread = s.mNumberOfUnreadPosts; + stat.mNumChildMsgsNew = 0; + stat.mNumChildMsgsUnread = 0; + + return true; } bool GxsChannelDialog::getGroupData(std::list& groupInfo) diff --git a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsModel.cpp b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsModel.cpp index 6179acae7..4e4636b8b 100644 --- a/retroshare-gui/src/gui/gxschannels/GxsChannelPostsModel.cpp +++ b/retroshare-gui/src/gui/gxschannels/GxsChannelPostsModel.cpp @@ -548,8 +548,9 @@ void RsGxsChannelPostsModel::setPosts(const RsGxsChannelGroup& group, std::vecto initEmptyHierarchy(); mChannelGroup = group; - createPostsArray(posts); +// createPostsArray(posts); + mPosts = posts; std::sort(mPosts.begin(),mPosts.end()); for(uint32_t i=0;i& posts) -{ - // collect new versions of posts if any - -#ifdef DEBUG_CHANNEL_MODEL - std::cerr << "Inserting channel posts" << std::endl; -#endif - - std::vector new_versions ; - for (uint32_t i=0;i search_map ; - for (uint32_t i=0;i versions ; - std::map::const_iterator vit ; - - while(search_map.end() != (vit=search_map.find(posts[current_index].mMeta.mOrigMsgId))) - { -#ifdef DEBUG_CHANNEL_MODEL - std::cerr << " post at index " << current_index << " replaces a post at position " << vit->second ; -#endif - - // Now replace the post only if the new versionis more recent. It may happen indeed that the same post has been corrected multiple - // times. In this case, we only need to replace the post with the newest version - - //uint32_t prev_index = current_index ; - current_index = vit->second ; - - if(posts[current_index].mMeta.mMsgId.isNull()) // This handles the branching situation where this post has been already erased. No need to go down further. - { -#ifdef DEBUG_CHANNEL_MODEL - std::cerr << " already erased. Stopping." << std::endl; -#endif - break ; - } - - if(posts[current_index].mMeta.mPublishTs < posts[source_index].mMeta.mPublishTs) - { -#ifdef DEBUG_CHANNEL_MODEL - std::cerr << " and is more recent => following" << std::endl; -#endif - for(std::set::const_iterator itt(posts[current_index].mOlderVersions.begin());itt!=posts[current_index].mOlderVersions.end();++itt) - posts[source_index].mOlderVersions.insert(*itt); - - posts[source_index].mOlderVersions.insert(posts[current_index].mMeta.mMsgId); - posts[current_index].mMeta.mMsgId.clear(); // clear the msg Id so the post will be ignored - } -#ifdef DEBUG_CHANNEL_MODEL - else - std::cerr << " but is older -> Stopping" << std::endl; -#endif - } - } - } - -#ifdef DEBUG_CHANNEL_MODEL - std::cerr << "Now adding " << posts.size() << " posts into array structure..." << std::endl; -#endif - - mPosts.clear(); - - for (std::vector::const_reverse_iterator it = posts.rbegin(); it != posts.rend(); ++it) - { - if(!(*it).mMeta.mMsgId.isNull()) - { -#ifdef DEBUG_CHANNEL_MODEL - std::cerr << " adding post \"" << (*it).mMeta.mMsgName << "\"" << std::endl; -#endif - mPosts.push_back(*it); - } -#ifdef DEBUG_CHANNEL_MODEL - else - std::cerr << " skipped older version post \"" << (*it).mMeta.mMsgName << "\"" << std::endl; -#endif - } -} - -void RsGxsChannelPostsModel::createPostsArray(std::vector& posts) -{ - // The hierarchy of posts may contain edited posts. In the new model (03/2023), mOrigMsgId points to the original - // top-level post in the hierarchy of edited posts. However, in the old model, mOrigMsgId points to the edited post. - // Therefore the algorithm below is made to cope with both models at once. - // - // In the future, using the new model, it will be possible to delete old versions from the db, and detect new versions - // because they all share the same mOrigMsgId. - // - // We proceed as follows: - // - // 1 - create a search map to convert post IDs into their index in the posts tab - // 2 - recursively climb up the post mOrigMsgId until no parent is found. At top level, create the original post, and add all previous elements as newer versions. - // 3 - go through the list of original posts, select among them the most recent version, and set all others as older versions. - // - // The algorithm handles the case where some parent has been deleted. - -#ifdef DEBUG_CHANNEL_MODEL - std::cerr << "Inserting channel posts" << std::endl; -#endif - - // 1 - create a search map to convert post IDs into their index in the posts tab - -#ifdef DEBUG_CHANNEL_MODEL - std::cerr << " Given list: " << std::endl; -#endif - std::map search_map ; - - for (uint32_t i=0;i > > original_versions ; - - for (uint32_t i=0;i& versions,rstime_t newest_time,uint32_t newest_index,int depth)> recurs_find_top_level - = [&posts,&search_map,&recurs_find_top_level,&original_versions](uint32_t index, - std::set& collected_versions, - rstime_t newest_time, - uint32_t newest_index, - int depth) - -> RsGxsMessageId - { - const auto& m(posts[index].mMeta); - - if(m.mPublishTs > newest_time) - { - newest_index = index; - newest_time = m.mPublishTs; - } - collected_versions.insert(m.mMsgId); - - RsGxsMessageId top_level_id; - std::map::const_iterator it; - - if(m.mOrigMsgId.isNull() || m.mOrigMsgId==m.mMsgId) // we have a top-level post. - top_level_id = m.mMsgId; - else if( (it = search_map.find(m.mOrigMsgId)) == search_map.end()) // we don't have the post. Never mind, we store the - { - top_level_id = m.mOrigMsgId; - collected_versions.insert(m.mOrigMsgId); // this one will never be added to the set by the previous call - } - else - { - top_level_id = recurs_find_top_level(it->second,collected_versions,newest_time,newest_index,depth+1); - posts[index].mMeta.mOrigMsgId = top_level_id; // this fastens calculation because it will skip already seen posts. - - return top_level_id; - } - -#ifdef DEBUG_CHANNEL_MODEL - std::cerr << std::string(2*depth,' ') << " top level = " << top_level_id ; -#endif - auto vit = original_versions.find(top_level_id); - - if(vit != original_versions.end()) - { - if(posts[vit->second.first].mMeta.mPublishTs < newest_time) - vit->second.first = newest_index; - -#ifdef DEBUG_CHANNEL_MODEL - std::cerr << " already existing. " << std::endl; -#endif - } - else - { - original_versions[top_level_id].first = newest_index; -#ifdef DEBUG_CHANNEL_MODEL - std::cerr << " new. " << std::endl; -#endif - } - original_versions[top_level_id].second.insert(collected_versions.begin(),collected_versions.end()); - - return top_level_id; - }; - - auto versions_set = std::set(); - recurs_find_top_level(i,versions_set,posts[i].mMeta.mPublishTs,i,0); - } - - mPosts.clear(); - -#ifdef DEBUG_CHANNEL_MODEL - std::cerr << " Total top_level posts: " << original_versions.size() << std::endl; - - for(auto it:original_versions) - { - std::cerr << " Post " << it.first << ". Total versions = " << it.second.second.size() << " latest: " << posts[it.second.first].mMeta.mMsgId << std::endl; - - for(auto m:it.second.second) - if(m != it.first) - std::cerr << " other (newer version): " << m << std::endl; - } -#endif - // make sure the posts are delivered in the same order they appears in the posts[] tab. - - std::vector ids; - - for(auto id:original_versions) - ids.push_back(id.second.first); - - std::sort(ids.begin(),ids.end()); - - for(uint32_t i=0;i