Commit 05317a74 authored by Sébastien Blin's avatar Sébastien Blin Committed by Philippe Gorley
Browse files

chatview: improve large history loading



When rendering large history, the webkitprocess is using a lot of
ressources and freeze during a few seconds.

This patch allows the user to directly have the ability to see
previous history and send messages while history is rendering.

Change-Id: I921070439328f7bfecb57bfbaec43c3dd88d2d14
Reviewed-by: Philippe Gorley's avatarPhilippe Gorley <philippe.gorley@savoirfairelinux.com>
parent d7bfa313
......@@ -297,8 +297,10 @@ print_text_recording(ChatView *self)
ChatViewPrivate *priv = CHAT_VIEW_GET_PRIVATE(self);
if (!priv->conversation_) return;
for (const auto& interaction : priv->conversation_->interactions)
print_interaction_to_buffer(self, interaction.first, interaction.second);
webkit_chat_container_print_history(
WEBKIT_CHAT_CONTAINER(priv->webkit_chat_container),
priv->conversation_->interactions
);
QObject::disconnect(priv->new_interaction_connection);
}
......
......@@ -24,6 +24,7 @@
#include <webkit2/webkit2.h>
// Qt
#include <QtCore/QJsonArray>
#include <QtCore/QJsonValue>
#include <QtCore/QJsonObject>
#include <QtCore/QJsonDocument>
......@@ -140,8 +141,8 @@ webview_chat_context_menu(G_GNUC_UNUSED WebKitChatContainer *self,
return false;
}
QString
interaction_to_json_interaction_object(const uint64_t msgId, const lrc::api::interaction::Info& interaction)
QJsonObject
build_interaction_json(const uint64_t msgId, const lrc::api::interaction::Info& interaction)
{
auto sender = QString(interaction.authorUri.c_str());
auto timestamp = QString::number(interaction.timestamp);
......@@ -191,10 +192,24 @@ interaction_to_json_interaction_object(const uint64_t msgId, const lrc::api::int
interaction_object.insert("delivery_status", QJsonValue("unknown"));
break;
}
return interaction_object;
}
QString
interaction_to_json_interaction_object(const uint64_t msgId, const lrc::api::interaction::Info& interaction)
{
auto interaction_object = build_interaction_json(msgId, interaction);
return QString(QJsonDocument(interaction_object).toJson(QJsonDocument::Compact));
}
QString
interactions_to_json_array_object(const std::map<uint64_t, lrc::api::interaction::Info> interactions) {
QJsonArray array;
for (const auto& interaction: interactions)
array.append(build_interaction_json(interaction.first, interaction.second));
return QString(QJsonDocument(array).toJson(QJsonDocument::Compact));
}
#if WEBKIT_CHECK_VERSION(2, 6, 0)
static gboolean
webview_chat_decide_policy (G_GNUC_UNUSED WebKitWebView *web_view,
......@@ -572,6 +587,23 @@ webkit_chat_container_print_new_interaction(WebKitChatContainer *view,
g_free(function_call);
}
void
webkit_chat_container_print_history(WebKitChatContainer *view, const std::map<uint64_t, lrc::api::interaction::Info> interactions)
{
WebKitChatContainerPrivate *priv = WEBKIT_CHAT_CONTAINER_GET_PRIVATE(view);
auto interactions_str = interactions_to_json_array_object(interactions).toUtf8();
gchar* function_call = g_strdup_printf("ring.chatview.printHistory(%s)", interactions_str.constData());
webkit_web_view_run_javascript(
WEBKIT_WEB_VIEW(priv->webview_chat),
function_call,
NULL,
NULL,
NULL
);
g_free(function_call);
}
void
webkit_chat_container_set_temporary(WebKitChatContainer *view, bool temporary)
{
......
......@@ -22,6 +22,7 @@
// Gtk
#include <gtk/gtk.h>
#include <map>
// LRC
#include <api/interaction.h>
......@@ -42,6 +43,7 @@ GtkWidget* webkit_chat_container_new (void);
void webkit_chat_container_clear (WebKitChatContainer *view);
void webkit_chat_container_clear_sender_images (WebKitChatContainer *view);
void webkit_chat_container_print_new_interaction(WebKitChatContainer *view, uint64_t msgId, const lrc::api::interaction::Info& interaction);
void webkit_chat_container_print_history (WebKitChatContainer *view, const std::map<uint64_t, lrc::api::interaction::Info> interactions);
void webkit_chat_container_update_interaction (WebKitChatContainer *view, uint64_t msgId, const lrc::api::interaction::Info& interaction);
void webkit_chat_container_set_sender_image (WebKitChatContainer *view, const std::string& sender, const std::string& senderImage);
gboolean webkit_chat_container_is_ready (WebKitChatContainer *view);
......
......@@ -83,6 +83,8 @@ ring.chatview = (function(){
var raf = window.requestAnimationFrame || window.webkitRequestAnimationFrame;
var messages = document.querySelector("#messages");
var displayLinksEnabled = false;
var historyBufferIndex = 0; // When showing a large amount of interactions, this counter store the interaction's index to show
var historyBuffer = []; // Before showing a large amount of interactions, this array is used as a buffer.
function setDisplayLinks(display) {
displayLinksEnabled = display;
......@@ -405,7 +407,7 @@ ring.chatview = (function(){
* Adds a message to the buffer, or update it if new_message is
* TRUE
*/
function addOrUpdateMessage(message_object, new_message)
function addOrUpdateMessage(message_object, new_message, insert_after = true)
{
// Properties of the message object
var message_id = message_object["id"],
......@@ -473,13 +475,7 @@ ring.chatview = (function(){
chatview_message_div.appendChild(chatview_message_sender_image);
chatview_message_div.appendChild(chatview_message_wrapper);
chatview_message_div.appendChild(chatview_message_delivery_status);
messages.appendChild(chatview_message_div);
// Get last message
const items = messages.querySelectorAll(".message");
// Add message
messages.appendChild(chatview_message_div);
// Get timestamp to add
const formattedTimestamp = getMessageTimestampText(message_timestamp, true);
// Create the timestamp object
......@@ -494,9 +490,15 @@ ring.chatview = (function(){
// Remove last timestamp if it's the same
if (messages.querySelectorAll(".timestamp"))
cleanPreviousTimestamps(date_elt, messages.children.length);
// Add the new timestamp
messages.appendChild(date_elt);
// Add message and the new timestamp
if (insert_after) {
messages.appendChild(chatview_message_div);
messages.appendChild(date_elt);
} else {
messages.insertBefore(date_elt, messages.firstChild);
messages.insertBefore(chatview_message_div, messages.firstChild);
}
} else {
chatview_message_div = document.querySelector("#message_" + message_id);
......@@ -574,6 +576,36 @@ ring.chatview = (function(){
}
}
/**
* Show the history in reverse order and avoid the process to consumes a lot of ressources
*/
function printHistoryPart () {
var previousScrollHeightMinusTop = messages.scrollHeight - messages.scrollTop;
// Show 10 messages
for (var i = 0; i < 10; ++i) {
addOrUpdateMessage(historyBuffer[historyBuffer.length - 1 - historyBufferIndex], true, false);
historyBufferIndex ++;
if (historyBufferIndex === historyBuffer.length)
break;
}
// Replace the scrollbar to the wanted position
messages.scrollTop = messages.scrollHeight - previousScrollHeightMinusTop;
// Make a short pause to minimizes ressources consumption
// show quickly the first hundred messages
if (historyBufferIndex !== historyBuffer.length)
setTimeout(printHistoryPart, (historyBufferIndex > 100) ? 100 : 1);
}
/**
* Show the whole history in the chatview.
*/
function printHistory(messages_array)
{
historyBuffer = messages_array;
historyBufferIndex = 0;
setTimeout(printHistoryPart, 1);
}
/**
* Updated a message that was previously added with addMessage
*/
......@@ -648,6 +680,7 @@ ring.chatview = (function(){
return {
addMessage: addMessage,
printHistory: printHistory,
updateMessage: updateMessage,
setSenderImage: setSenderImage,
setSendIcon: setSendIcon,
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment