attempt at not reloading full channel data at every change

This commit is contained in:
csoler 2023-02-09 23:27:43 +01:00
parent 9442d87644
commit c06da99757
5 changed files with 520 additions and 479 deletions

View File

@ -118,85 +118,21 @@ void RsGxsChannelPostsModel::handleEvent_main_thread(std::shared_ptr<const RsEve
switch(e->mChannelEventCode)
{
case RsChannelEventCode::UPDATED_MESSAGE:
case RsChannelEventCode::READ_STATUS_CHANGED:
{
// Normally we should just emit dataChanged() on the index of the data that has changed:
// We need to update the data!
case RsChannelEventCode::READ_STATUS_CHANGED:
case RsChannelEventCode::NEW_COMMENT:
{
// Normally we should just emit dataChanged() on the index of the data that has changed:
// We need to update the data!
// make a copy of e, so as to avoid destruction of the shared pointer during async thread execution, since [e] doesn't actually tell
// the original shared_ptr that it is copied! So no counter is updated in event, which will be destroyed (as e will be) during or even before
// the execution of the lambda.
// In particular, mChannelMsgId may refer to a comment, but this will be handled correctly
// by update_single_post which will automatically retrive the correct parent msg.
RsGxsChannelEvent E(*e);
if(e->mChannelGroupId == mChannelGroup.mMeta.mGroupId)
update_single_post(e->mChannelGroupId,e->mChannelMsgId,e->mChannelThreadId);
};
break;
if(E.mChannelGroupId == mChannelGroup.mMeta.mGroupId)
RsThread::async([this, E]()
{
// 1 - get message data from p3GxsChannels. No need for pointers here, because we send only a single post to postToObject()
// At this point we dont know what kind of msg id we have. It can be a vote, a comment or an actual message.
std::vector<RsGxsChannelPost> posts;
std::vector<RsGxsComment> comments;
std::vector<RsGxsVote> votes;
std::set<RsGxsMessageId> msg_ids{ E.mChannelMsgId };
if(!rsGxsChannels->getChannelContent(E.mChannelGroupId,msg_ids, posts,comments,votes))
{
std::cerr << __PRETTY_FUNCTION__ << " failed to retrieve channel message data for channel/msg " << E.mChannelGroupId << "/" << E.mChannelMsgId << std::endl;
return;
}
// Check if what we have actually is a comment or a vote. If so we need to update the actual message they refer to
if(posts.empty()) // means we have a comment or a vote
{
msg_ids.clear();
for(auto c:comments) msg_ids.insert(c.mMeta.mThreadId);
for(auto v:votes ) msg_ids.insert(v.mMeta.mThreadId);
comments.clear();
votes.clear();
if(!rsGxsChannels->getChannelContent(E.mChannelGroupId,msg_ids,posts,comments,votes))
{
std::cerr << __PRETTY_FUNCTION__ << " failed to retrieve channel message data for channel/msg " << E.mChannelGroupId << "/" << E.mChannelMsgId << std::endl;
return;
}
}
// Need to call this in order to get the actuall comment count. The previous call only retrieves the message, since we supplied the message ID.
// another way to go would be to save the comment ids of the existing message and re-insert them before calling getChannelContent.
if(!rsGxsChannels->getChannelComments(E.mChannelGroupId,msg_ids,comments))
{
std::cerr << __PRETTY_FUNCTION__ << " failed to retrieve message comment data for channel/msg " << E.mChannelGroupId << "/" << E.mChannelMsgId << std::endl;
return;
}
updateCommentCounts(posts,comments);
// 2 - update the model in the UI thread.
RsQThreadUtils::postToObject( [posts,this]()
{
for(uint32_t i=0;i<posts.size();++i)
{
// linear search. Not good at all, but normally this is for a single post.
for(uint32_t j=0;j<mPosts.size();++j)
if(mPosts[j].mMeta.mMsgId == posts[i].mMeta.mMsgId)
{
mPosts[j] = posts[i];
triggerViewUpdate();
}
}
},this);
});
}
default:
default:
break;
}
}
@ -564,6 +500,47 @@ bool operator<(const RsGxsChannelPost& p1,const RsGxsChannelPost& p2)
return p1.mMeta.mPublishTs > p2.mMeta.mPublishTs;
}
void RsGxsChannelPostsModel::setSinglePost(const RsGxsChannelGroup& group, const RsGxsChannelPost& post)
{
if(mChannelGroup.mMeta.mGroupId != group.mMeta.mGroupId)
return;
preMods();
// This is potentially quadratic, so it should not be called many times!
bool found=false;
for(auto& p:mPosts)
if(post.mMeta.mMsgId == p.mMeta.mMsgId || post.mMeta.mOrigMsgId == p.mMeta.mMsgId)
{
p = post;
found = true;
}
if(!found)
mPosts.push_back(post);
std::sort(mPosts.begin(),mPosts.end());
mFilteredPosts.clear();
for(uint32_t i=0;i<mPosts.size();++i)
mFilteredPosts.push_back(i);
#ifdef DEBUG_CHANNEL_MODEL
// debug_dump();
#endif
if (rowCount()>0)
{
beginInsertRows(QModelIndex(),0,rowCount()-1);
endInsertRows();
}
postMods();
emit channelPostsLoaded();
}
void RsGxsChannelPostsModel::setPosts(const RsGxsChannelGroup& group, std::vector<RsGxsChannelPost>& posts)
{
preMods();
@ -593,6 +570,57 @@ void RsGxsChannelPostsModel::setPosts(const RsGxsChannelGroup& group, std::vecto
emit channelPostsLoaded();
}
void RsGxsChannelPostsModel::update_single_post(const RsGxsGroupId& group_id,const RsGxsMessageId& msg_id,const RsGxsMessageId& thread_id)
{
RsThread::async([this, group_id, msg_id,thread_id]()
{
// 1 - get message data from p3GxsChannels. No need for pointers here, because we send only a single post to postToObject()
// At this point we dont know what kind of msg id we have. It can be a vote, a comment or an actual message.
std::vector<RsGxsChannelPost> posts;
std::vector<RsGxsComment> comments;
std::vector<RsGxsVote> votes;
std::set<RsGxsMessageId> msg_ids({ (thread_id.isNull())?msg_id:thread_id } ); // we have a post message
if(!rsGxsChannels->getChannelContent(group_id,msg_ids, posts,comments,votes))
{
std::cerr << __PRETTY_FUNCTION__ << " failed to retrieve channel message data for channel/msg " << group_id << "/" << msg_id << std::endl;
return;
}
// Need to call this in order to get the actual comment count. The previous call only retrieves the message, since we supplied the message ID.
// another way to go would be to save the comment ids of the existing message and re-insert them before calling getChannelContent.
if(!rsGxsChannels->getChannelComments(group_id,msg_ids,comments))
{
std::cerr << __PRETTY_FUNCTION__ << " failed to retrieve message comment data for channel/msg " << group_id << "/" << msg_id << std::endl;
return;
}
// Normally, there's a single post in the "post" array. The function below takes a full array of posts however.
updateCommentCounts(posts,comments);
// 2 - update the model in the UI thread.
RsQThreadUtils::postToObject( [posts,this]()
{
for(uint32_t i=0;i<posts.size();++i)
{
// linear search. Not good at all, but normally this is for a single post.
for(uint32_t j=0;j<mPosts.size();++j)
if(mPosts[j].mMeta.mMsgId == posts[i].mMeta.mMsgId)
{
mPosts[j] = posts[i];
triggerViewUpdate();
}
}
},this);
});
}
void RsGxsChannelPostsModel::update_posts(const RsGxsGroupId& group_id)
{
if(group_id.isNull())

View File

@ -214,6 +214,7 @@ private:
static void computeReputationLevel(uint32_t forum_sign_flags, RsGxsChannelPost& entry);
void update_posts(const RsGxsGroupId& group_id);
void update_single_post(const RsGxsGroupId& group_id, const RsGxsMessageId& msgId, const RsGxsMessageId &thread_id);
#ifdef TODO
void setForumMessageSummary(const std::vector<RsGxsForumMsg>& messages);
@ -231,7 +232,8 @@ private:
//void computeMessagesHierarchy(const RsGxsChannelGroup& forum_group, const std::vector<RsMsgMetaData> &msgs_array, std::vector<ChannelPostsModelPostEntry> &posts, std::map<RsGxsMessageId, std::vector<std::pair<time_t, RsGxsMessageId> > > &mPostVersions);
void createPostsArray(std::vector<RsGxsChannelPost> &posts);
void setPosts(const RsGxsChannelGroup& group, std::vector<RsGxsChannelPost> &posts);
void initEmptyHierarchy();
void setSinglePost(const RsGxsChannelGroup& group, const RsGxsChannelPost& post);
void initEmptyHierarchy();
void handleEvent_main_thread(std::shared_ptr<const RsEvent> event);
std::vector<int> mFilteredPosts; // stores the list of displayes indices due to filtering.

View File

@ -104,11 +104,11 @@ public:
/* GxsMessageFrameWidget */
virtual QIcon groupIcon() override;
virtual void groupIdChanged() override { updateDisplay(true); }
virtual void groupIdChanged() override { updateDisplay(true,true); }
virtual QString groupName(bool) override;
virtual bool navigate(const RsGxsMessageId&) override;
void updateDisplay(bool complete);
void updateDisplay(bool update_group_data, bool update_posts);
#ifdef TODO
/* FeedHolder */
@ -141,7 +141,7 @@ protected:
private slots:
void showPostDetails();
void updateGroupData();
void updateData(bool update_group_data,bool update_posts);
void download();
void updateDAll_PB();
void createMsg();

View File

@ -194,7 +194,7 @@
<item>
<widget class="QTabWidget" name="channel_TW">
<property name="currentIndex">
<number>1</number>
<number>0</number>
</property>
<widget class="QWidget" name="tab_3">
<attribute name="title">
@ -402,7 +402,7 @@
<string notr="true">&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
p, li { white-space: pre-wrap; }
&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;&quot;&gt;
&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Ubuntu'; font-size:11pt; font-weight:400; font-style:normal;&quot;&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:8pt;&quot;&gt;Description&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="textInteractionFlags">