chatview: Add data transfer support
Add the ability to send and receives files via the chatview.
Change-Id: I529b3e1c75030c3bc2c5e535e9e9584dde9bb4cb
Reviewed-by: Philippe Gorley <philippe.gorley@savoirfairelinux.com>
diff --git a/src/chatview.cpp b/src/chatview.cpp
index 23d7f23..3d7b006 100644
--- a/src/chatview.cpp
+++ b/src/chatview.cpp
@@ -25,6 +25,9 @@
// std
#include <algorithm>
+// GTK
+#include <glib/gi18n.h>
+
// LRC
#include <api/contactmodel.h>
#include <api/conversationmodel.h>
@@ -160,6 +163,34 @@
priv->accountContainer_->info.conversationModel->makePermanent(priv->conversation_->uid);
}
+static gchar*
+file_to_manipulate(GtkWindow* top_window, bool send)
+{
+ GtkWidget* dialog;
+ GtkFileChooserAction action = send? GTK_FILE_CHOOSER_ACTION_OPEN : GTK_FILE_CHOOSER_ACTION_SAVE;
+ gint res;
+ gchar* filename = nullptr;
+
+ dialog = gtk_file_chooser_dialog_new(send? _("Send File") : _("Save File"),
+ top_window,
+ action,
+ _("_Cancel"),
+ GTK_RESPONSE_CANCEL,
+ send? _("_Open"): _("_Save"),
+ GTK_RESPONSE_ACCEPT,
+ nullptr);
+
+ res = gtk_dialog_run (GTK_DIALOG(dialog));
+
+ if (res == GTK_RESPONSE_ACCEPT) {
+ auto chooser = GTK_FILE_CHOOSER(dialog);
+ filename = gtk_file_chooser_get_filename(chooser);
+ }
+ gtk_widget_destroy (dialog);
+
+ return filename;
+}
+
static void
webkit_chat_container_script_dialog(G_GNUC_UNUSED GtkWidget* webview, gchar *interaction, ChatView* self)
{
@@ -176,6 +207,42 @@
// Get text body
auto toSend = order.substr(std::string("SEND:").size());
priv->accountContainer_->info.conversationModel->sendMessage(priv->conversation_->uid, toSend);
+ } else if (order.find("SEND_FILE") == 0) {
+ if (auto model = priv->accountContainer_->info.conversationModel.get()) {
+ if (auto filename = file_to_manipulate(GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(self))), true))
+ model->sendFile(priv->conversation_->uid, filename, g_path_get_basename(filename));
+ }
+ } else if (order.find("ACCEPT_FILE:") == 0) {
+ if (auto model = priv->accountContainer_->info.conversationModel.get()) {
+ try {
+ auto interactionId = std::stoull(order.substr(std::string("ACCEPT_FILE:").size()));
+ if (auto filename = file_to_manipulate(GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(self))), false))
+ model->acceptTransfer(priv->conversation_->uid, interactionId, filename);
+ else
+ model->cancelTransfer(priv->conversation_->uid, interactionId);
+ } catch (...) {
+ // ignore
+ }
+ }
+ } else if (order.find("REFUSE_FILE:") == 0) {
+ if (auto model = priv->accountContainer_->info.conversationModel.get()) {
+ try {
+ auto interactionId = std::stoull(order.substr(std::string("REFUSE_FILE:").size()));
+ model->cancelTransfer(priv->conversation_->uid, interactionId);
+ } catch (...) {
+ // ignore
+ }
+ }
+ } else if (order.find("OPEN_FILE:") == 0) {
+ // Get text body
+ auto filename {"file://" + order.substr(std::string("OPEN_FILE:").size())};
+ filename.erase(std::find_if(filename.rbegin(), filename.rend(),
+ std::not1(std::ptr_fun<int, int>(std::isspace))).base(), filename.end());
+ GError* error = nullptr;
+ if (!gtk_show_uri(nullptr, filename.c_str(), GDK_CURRENT_TIME, &error)) {
+ g_debug("Could not open file: %s", error->message);
+ g_error_free(error);
+ }
}
}
@@ -242,6 +309,7 @@
webkit_chat_container_print_new_interaction(
WEBKIT_CHAT_CONTAINER(priv->webkit_chat_container),
+ *priv->accountContainer_->info.conversationModel,
interactionId,
interaction
);
@@ -253,6 +321,7 @@
ChatViewPrivate *priv = CHAT_VIEW_GET_PRIVATE(self);
webkit_chat_container_update_interaction(
WEBKIT_CHAT_CONTAINER(priv->webkit_chat_container),
+ *priv->accountContainer_->info.conversationModel,
interactionId,
interaction
);
@@ -299,6 +368,7 @@
if (!priv->conversation_) return;
webkit_chat_container_print_history(
WEBKIT_CHAT_CONTAINER(priv->webkit_chat_container),
+ *priv->accountContainer_->info.conversationModel,
priv->conversation_->interactions
);
diff --git a/src/ringmainwindow.cpp b/src/ringmainwindow.cpp
index c7be93a..2c58072 100644
--- a/src/ringmainwindow.cpp
+++ b/src/ringmainwindow.cpp
@@ -1001,7 +1001,7 @@
gtk_combo_box_set_model(
GTK_COMBO_BOX(widgets->combobox_account_selector),
- GTK_TREE_MODEL (store)
+ GTK_TREE_MODEL(store)
);
gtk_combo_box_set_active(GTK_COMBO_BOX(widgets->combobox_account_selector), selection_row);
gtk_widget_set_visible(widgets->combobox_account_selector, show && enabled_accounts > 1);
diff --git a/src/webkitchatcontainer.cpp b/src/webkitchatcontainer.cpp
index bd58fc2..f8700ef 100644
--- a/src/webkitchatcontainer.cpp
+++ b/src/webkitchatcontainer.cpp
@@ -31,6 +31,7 @@
// LRC
#include <globalinstances.h>
+#include <api/conversationmodel.h>
// Ring Client
#include "native/pixbufmanipulator.h"
@@ -142,7 +143,9 @@
}
QJsonObject
-build_interaction_json(const uint64_t msgId, const lrc::api::interaction::Info& interaction)
+build_interaction_json(lrc::api::ConversationModel& conversation_model,
+ const uint64_t msgId,
+ const lrc::api::interaction::Info& interaction)
{
auto sender = QString(interaction.authorUri.c_str());
auto timestamp = QString::number(interaction.timestamp);
@@ -155,6 +158,7 @@
interaction_object.insert("sender_contact_method", QJsonValue(sender));
interaction_object.insert("timestamp", QJsonValue(timestamp));
interaction_object.insert("direction", QJsonValue(direction));
+
switch (interaction.type)
{
case lrc::api::interaction::Type::TEXT:
@@ -166,11 +170,23 @@
case lrc::api::interaction::Type::CONTACT:
interaction_object.insert("type", QJsonValue("contact"));
break;
+ case lrc::api::interaction::Type::OUTGOING_DATA_TRANSFER:
+ case lrc::api::interaction::Type::INCOMING_DATA_TRANSFER: {
+ interaction_object.insert("type", QJsonValue("data_transfer"));
+ lrc::api::datatransfer::Info info = {};
+ conversation_model.getTransferInfo(msgId, info);
+ if (info.status != lrc::api::datatransfer::Status::INVALID) {
+ interaction_object.insert("totalSize", QJsonValue(qint64(info.totalSize)));
+ interaction_object.insert("progress", QJsonValue(qint64(info.progress)));
+ }
+ break;
+ }
case lrc::api::interaction::Type::INVALID:
default:
interaction_object.insert("type", QJsonValue(""));
break;
}
+
switch (interaction.status)
{
case lrc::api::interaction::Status::READ:
@@ -180,11 +196,33 @@
interaction_object.insert("delivery_status", QJsonValue("sent"));
break;
case lrc::api::interaction::Status::FAILED:
+ case lrc::api::interaction::Status::TRANSFER_ERROR:
interaction_object.insert("delivery_status", QJsonValue("failure"));
break;
+ case lrc::api::interaction::Status::TRANSFER_UNJOINABLE_PEER:
+ interaction_object.insert("delivery_status", QJsonValue("unjoinable peer"));
+ break;
case lrc::api::interaction::Status::SENDING:
interaction_object.insert("delivery_status", QJsonValue("sending"));
break;
+ case lrc::api::interaction::Status::TRANSFER_CREATED:
+ interaction_object.insert("delivery_status", QJsonValue("connecting"));
+ break;
+ case lrc::api::interaction::Status::TRANSFER_ACCEPTED:
+ interaction_object.insert("delivery_status", QJsonValue("accepted"));
+ break;
+ case lrc::api::interaction::Status::TRANSFER_CANCELED:
+ interaction_object.insert("delivery_status", QJsonValue("canceled"));
+ break;
+ case lrc::api::interaction::Status::TRANSFER_ONGOING:
+ interaction_object.insert("delivery_status", QJsonValue("ongoing"));
+ break;
+ case lrc::api::interaction::Status::TRANSFER_AWAITING:
+ interaction_object.insert("delivery_status", QJsonValue("awaiting"));
+ break;
+ case lrc::api::interaction::Status::TRANSFER_FINISHED:
+ interaction_object.insert("delivery_status", QJsonValue("finished"));
+ break;
case lrc::api::interaction::Status::INVALID:
case lrc::api::interaction::Status::UNKNOWN:
case lrc::api::interaction::Status::UNREAD:
@@ -196,17 +234,20 @@
}
QString
-interaction_to_json_interaction_object(const uint64_t msgId, const lrc::api::interaction::Info& interaction)
+interaction_to_json_interaction_object(lrc::api::ConversationModel& conversation_model,
+ const uint64_t msgId,
+ const lrc::api::interaction::Info& interaction)
{
- auto interaction_object = build_interaction_json(msgId, interaction);
+ auto interaction_object = build_interaction_json(conversation_model, 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) {
+interactions_to_json_array_object(lrc::api::ConversationModel& conversation_model,
+ 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));
+ array.append(build_interaction_json(conversation_model, interaction.first, interaction.second));
return QString(QJsonDocument(array).toJson(QJsonDocument::Compact));
}
@@ -551,12 +592,13 @@
void
webkit_chat_container_update_interaction(WebKitChatContainer *view,
+ lrc::api::ConversationModel& conversation_model,
uint64_t msgId,
const lrc::api::interaction::Info& interaction)
{
WebKitChatContainerPrivate *priv = WEBKIT_CHAT_CONTAINER_GET_PRIVATE(view);
- auto interaction_object = interaction_to_json_interaction_object(msgId, interaction).toUtf8();
+ auto interaction_object = interaction_to_json_interaction_object(conversation_model, msgId, interaction).toUtf8();
gchar* function_call = g_strdup_printf("ring.chatview.updateMessage(%s);", interaction_object.constData());
webkit_web_view_run_javascript(
WEBKIT_WEB_VIEW(priv->webview_chat),
@@ -570,12 +612,13 @@
void
webkit_chat_container_print_new_interaction(WebKitChatContainer *view,
+ lrc::api::ConversationModel& conversation_model,
uint64_t msgId,
const lrc::api::interaction::Info& interaction)
{
WebKitChatContainerPrivate *priv = WEBKIT_CHAT_CONTAINER_GET_PRIVATE(view);
- auto interaction_object = interaction_to_json_interaction_object(msgId, interaction).toUtf8();
+ auto interaction_object = interaction_to_json_interaction_object(conversation_model, msgId, interaction).toUtf8();
gchar* function_call = g_strdup_printf("ring.chatview.addMessage(%s);", interaction_object.constData());
webkit_web_view_run_javascript(
WEBKIT_WEB_VIEW(priv->webview_chat),
@@ -588,11 +631,13 @@
}
void
-webkit_chat_container_print_history(WebKitChatContainer *view, const std::map<uint64_t, lrc::api::interaction::Info> interactions)
+webkit_chat_container_print_history(WebKitChatContainer *view,
+ lrc::api::ConversationModel& conversation_model,
+ 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();
+ auto interactions_str = interactions_to_json_array_object(conversation_model, 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),
diff --git a/src/webkitchatcontainer.h b/src/webkitchatcontainer.h
index 5afaa47..6efefde 100644
--- a/src/webkitchatcontainer.h
+++ b/src/webkitchatcontainer.h
@@ -27,6 +27,10 @@
// LRC
#include <api/interaction.h>
+namespace lrc { namespace api {
+class ConversationModel;
+}};
+
G_BEGIN_DECLS
#define WEBKIT_CHAT_CONTAINER_TYPE (webkit_chat_container_get_type ())
@@ -42,9 +46,9 @@
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_print_new_interaction(WebKitChatContainer *view, lrc::api::ConversationModel& conversation_model, uint64_t msgId, const lrc::api::interaction::Info& interaction);
+void webkit_chat_container_update_interaction (WebKitChatContainer *view, lrc::api::ConversationModel& conversation_model, uint64_t msgId, const lrc::api::interaction::Info& interaction);
+void webkit_chat_container_print_history (WebKitChatContainer *view, lrc::api::ConversationModel& conversation_model, const std::map<uint64_t, lrc::api::interaction::Info> interactions);
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);
void webkit_chat_container_set_display_links (WebKitChatContainer *view, bool display);
diff --git a/web/chatview.css b/web/chatview.css
index ba4af18..07be2e5 100644
--- a/web/chatview.css
+++ b/web/chatview.css
@@ -32,7 +32,6 @@
color: white;
padding: 10px 20px 10px 20px;
vertical-align: middle;
-
}
.button-green {
@@ -169,7 +168,7 @@
color: #d3d3d3;
}
-#sendBtn {
+.msg-button {
border-radius: 50%;
border: 0;
width: 40px;
@@ -178,13 +177,13 @@
transition: all 0.3s ease;
}
-#sendBtn.hover,
-#sendBtn:hover {
+.msg-button.hover,
+.msg-button:hover {
background: #bae5f0;
}
-#sendBtn.hover svg,
-#sendBtn:hover svg {
+.msg-button.hover svg,
+.msg-button:hover svg {
fill: black;
}
@@ -502,26 +501,34 @@
width: 100%;
}
+.message_type_data_transfer .message_timestamp,
+.message_type_data_transfer .message_delivery_status,
+.message_type_data_transfer .sent-checkmark,
.message_type_call .sent-checkmark,
.message_type_call .message_sender,
.message_type_call .message_delivery_status,
.message_type_call .message_timestamp,
.message_type_call .message_sender_image,
+.message_type_call .message_progress_bar,
.message_type_contact .sent-checkmark,
.message_type_contact .message_sender,
.message_type_contact .message_delivery_status,
.message_type_contact .message_timestamp,
-.message_type_contact .message_sender_image {
+.message_type_contact .message_sender_image,
+.message_type_contact .message_progress_bar,
+.message_type_text .message_progress_bar {
visibility: hidden;
display: none;
}
.message_type_contact .message_wrapper:before,
+.message_type_data_transfer .message_wrapper:before,
.message_type_call .message_wrapper:before {
display: none;
}
.message_type_call .message_wrapper:after,
+.message_type_data_transfer .message_wrapper:after,
.message_type_contact .message_wrapper:after {
display: none;
}
@@ -561,3 +568,63 @@
color: red;
font-size: 1.25em;
}
+
+.message_type_data_transfer .message_wrapper
+{
+ padding: 0;
+ width: 30%;
+ display: flex;
+ flex-wrap: wrap;
+}
+
+.message_type_data_transfer #left_buttons
+{
+ width: 25%;
+ display: flex;
+ padding-left: 5px;
+ overflow: hidden;
+}
+
+.message_type_data_transfer #text
+{
+ width: 70%;
+ text-align: center;
+ padding-top: 14px;
+ margin-bottom: 12px;
+}
+
+.message_type_data_transfer #filename
+{
+ font-weight: bold;
+ overflow: hidden;
+}
+
+.message_type_data_transfer #informations
+{
+ color: #555;
+ font-size: 0.8em;
+}
+
+.message_progress_bar {
+ margin-top: 12px;
+ width: 100%;
+ height: 12px;
+ position: relative;
+ overflow: hidden;
+ background-color: #eee;
+ border-radius: 2px;
+ box-shadow: 0 2px 5px rgba(0, 0, 0, 0.25) inset;
+}
+
+.message_progress_bar > span {
+ display: inline;
+ height: 100%;
+ background-color: #01a2b8;
+ position: absolute;
+ overflow: hidden;
+}
+
+.message_type_data_transfer .flat-button
+{
+ padding: 0;
+}
diff --git a/web/chatview.html b/web/chatview.html
index 435ac79..721457e 100644
--- a/web/chatview.html
+++ b/web/chatview.html
@@ -20,11 +20,17 @@
<div id="sendMessage">
<textarea id="message" autofocus placeholder="Message" onkeyup="grow_text_area()" rows="1" disabled="false"></textarea>
- <div id="sendBtn" onclick="ring.chatview.sendMessage()" title="Send">
+ <div id="sendBtn" class="msg-button" onclick="ring.chatview.sendMessage()" title="Send">
<svg viewBox="0 0 30 30" xmlns="http://www.w3.org/2000/svg">
<path xmlns="http://www.w3.org/2000/svg" d="M12,11.874v4.357l7-6.69l-7-6.572v3.983c-8.775,0-11,9.732-11,9.732C3.484,12.296,7.237,11.874,12,11.874z"/>
</svg>
</div>
+ <div id="send-file-btn" class="msg-button" onclick="ring.chatview.sendFile()" title="Send File">
+ <svg viewBox="0 0 30 30" xmlns="http://www.w3.org/2000/svg">
+ <path d="M0 0h24v24H0z" fill="none"/>
+ <path d="M9 16h6v-6h4l-7-7-7 7h4zm-4 2h14v2H5z"/>
+ </svg>
+ </div>
</div>
</form>
</div>
@@ -283,22 +289,22 @@
}
}
- /**
- * Returns HTML message from the message text.
- * Cleaned and linkified.
- */
- function getMessageHtml(message_text)
- {
- const escaped_message = escapeHtml(message_text);
- var linkified_message = linkifyHtml(escaped_message, {});
+ /**
+ * Returns HTML message from the message text.
+ * Cleaned and linkified.
+ */
+ function getMessageHtml(message_text)
+ {
+ const escaped_message = escapeHtml(message_text);
+ var linkified_message = linkifyHtml(escaped_message, {});
- const textPart = document.createElement('pre');
- var linkified_message = linkified_message.replace("📞", "<span id=\"green\">📞</span>")
- var linkified_message = linkified_message.replace("🕽", "<span id=\"red\">🕽</span>")
- textPart.innerHTML = linkified_message;
+ const textPart = document.createElement('pre');
+ var linkified_message = linkified_message.replace("📞", "<span id=\"green\">📞</span>")
+ var linkified_message = linkified_message.replace("🕽", "<span id=\"red\">🕽</span>")
+ textPart.innerHTML = linkified_message;
- return textPart.outerHTML;
- }
+ return textPart.outerHTML;
+ }
/**
* Returns the message status, formatted for display
@@ -309,19 +315,17 @@
switch(message_delivery_status)
{
- case "unknown":
- formatted_delivery_status = "";
- break;
case "sending":
- formatted_delivery_status = "Sending<svg overflow='visible' viewBox='0 -2 16 14' height='16px' width='16px'><circle class='status_circle anim-first' cx='4' cy='12' r='1'/><circle class='status_circle anim-second' cx='8' cy='12' r='1'/><circle class='status_circle anim-third' cx='12' cy='12' r='1'/></svg>"
- break;
- case "read":
- formatted_delivery_status = "";
+ case "ongoing":
+ formatted_delivery_status = "Sending<svg overflow='visible' viewBox='0 -2 16 14' height='16px' width='16px'><circle class='status_circle anim-first' cx='4' cy='12' r='1'/><circle class='status_circle anim-second' cx='8' cy='12' r='1'/><circle class='status_circle anim-third' cx='12' cy='12' r='1'/></svg>";
break;
case "failure":
- formatted_delivery_status = "Failure <svg overflow='visible' viewBox='0 -2 16 14' height='16px' width='16px'><path class='status-x x-first' stroke='#AA0000' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' fill='none' d='M4,4 L12,12'/><path class='status-x x-second' stroke='#AA0000' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' fill='none' d='M12,4 L4,12'/></svg>"
+ formatted_delivery_status = "Failure <svg overflow='visible' viewBox='0 -2 16 14' height='16px' width='16px'><path class='status-x x-first' stroke='#AA0000' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' fill='none' d='M4,4 L12,12'/><path class='status-x x-second' stroke='#AA0000' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' fill='none' d='M12,4 L4,12'/></svg>";
break;
case "sent":
+ case "finished":
+ case "unknown":
+ case "read":
formatted_delivery_status = "";
break;
default:
@@ -403,6 +407,115 @@
}
}
+ /**
+ * Convert a value in filesize
+ */
+ function humanFileSize(bytes) {
+ var thresh = 1024;
+ if(Math.abs(bytes) < thresh) {
+ return bytes + ' B';
+ }
+ var units = ['kB','MB','GB','TB','PB','EB','ZB','YB']
+ var u = -1;
+ do {
+ bytes /= thresh;
+ ++u;
+ } while(Math.abs(bytes) >= thresh && u < units.length - 1);
+ return bytes.toFixed(1)+' '+units[u];
+ }
+
+ /**
+ * Change the value of the progress bar
+ */
+ function updateProgressBar(progress_bar, message_object, message_delivery_status) {
+ var delivery_status = message_object["delivery_status"];
+ if ("progress" in message_object && !isErrorStatus(delivery_status) && message_object["progress"] !== 100) {
+ var progress_percent = (100 * message_object["progress"] / message_object["totalSize"]);
+ if (progress_percent !== 100)
+ progress_bar.childNodes[0].setAttribute("style", "width: " + progress_percent + "%");
+ else
+ progress_bar.setAttribute("style", "display: none");
+ } else
+ progress_bar.setAttribute("style", "display: none");
+ }
+
+ /**
+ * Check if a status is an error status
+ */
+ function isErrorStatus(status) {
+ return (status === 'failure'
+ || status === 'canceled'
+ || status === 'unjoinable peer');
+ }
+
+ /**
+ * Update a data transfer interaction
+ */
+ function updateDataTransferInteraction(message_div, message_object) {
+ var acceptSvg = '<svg fill="#ffffff" height="36" viewBox="0 0 24 24" width="36" xmlns="http://www.w3.org/2000/svg" style="width:50%; display:block; margin:auto;"><path d="M0 0h24v24H0z" fill="none"/><path d="M9 16.2L4.8 12l-1.4 1.4L9 19 21 7l-1.4-1.4L9 16.2z"/></svg>',
+ refuseSvg = '<svg fill="#ffffff" height="36" viewBox="0 0 24 24" width="36" xmlns="http://www.w3.org/2000/svg" style="width:50%; display:block; margin:auto;"><path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/><path d="M0 0h24v24H0z" fill="none"/></svg>',
+ fileSvg = '<svg fill="#000000" height="36" viewBox="0 0 24 24" width="36" xmlns="http://www.w3.org/2000/svg" style="width:50%;"><path d="M16.5 6v11.5c0 2.21-1.79 4-4 4s-4-1.79-4-4V5c0-1.38 1.12-2.5 2.5-2.5s2.5 1.12 2.5 2.5v10.5c0 .55-.45 1-1 1s-1-.45-1-1V6H10v9.5c0 1.38 1.12 2.5 2.5 2.5s2.5-1.12 2.5-2.5V5c0-2.21-1.79-4-4-4S7 2.79 7 5v12.5c0 3.04 2.46 5.5 5.5 5.5s5.5-2.46 5.5-5.5V6h-1.5z"/><path d="M0 0h24v24H0z" fill="none"/></svg>',
+ warningSvg = '<svg fill="#000000" height="36" viewBox="0 0 24 24" width="36" xmlns="http://www.w3.org/2000/svg" style="width:50%;"><path d="M0 0h24v24H0z" fill="none"/><path d="M1 21h22L12 2 1 21zm12-3h-2v-2h2v2zm0-4h-2v-4h2v4z"/></svg>',
+ incomingSvg = '<svg fill="#000000" height="36" viewBox="0 0 24 24" width="36" xmlns="http://www.w3.org/2000/svg" style="width:50%;"><path d="M0 0h24v24H0z" fill="none"/><path d="M20 5.41L18.59 4 7 15.59V9H5v10h10v-2H8.41z"/></svg>',
+ outgoingSvg = '<svg fill="#000000" height="36" viewBox="0 0 24 24" width="36" xmlns="http://www.w3.org/2000/svg" style="width:50%;"><path d="M0 0h24v24H0z" fill="none"/><path d="M9 5v2h6.59L4 18.59 5.41 20 17 8.41V15h2V5z"/></svg>';
+ var message_delivery_status = message_object["delivery_status"];
+ var message_direction = message_object["direction"];
+ var message_id = message_object["id"];
+
+ // Set informations text
+ var informations_div = message_div.querySelector("#informations");
+ var informations_txt = getMessageTimestampText(message_object["timestamp"], true);
+ if (message_object["totalSize"] && message_object["progress"]) {
+ if (message_delivery_status === 'finished') {
+ informations_txt += " - " + humanFileSize(message_object["totalSize"]);
+ } else {
+ informations_txt += " - " + humanFileSize(message_object["progress"])
+ + " / " + humanFileSize(message_object["totalSize"]);
+ }
+ }
+ informations_txt += " - " + message_delivery_status;
+ informations_div.innerText = informations_txt;
+
+ // Update flat buttons
+ var left_buttons = message_div.querySelector("#left_buttons");
+ left_buttons.innerHTML = '';
+ if (message_delivery_status === 'awaiting') {
+ // add buttons to accept or refuse a call.
+ var accept_button = document.createElement('div');
+ accept_button.innerHTML = acceptSvg;
+ accept_button.setAttribute("id", "accept-btn");
+ accept_button.setAttribute("title", "Accept");
+ accept_button.setAttribute("class", "flat-button button-green");
+ accept_button.onclick = function() {
+ window.prompt('ACCEPT_FILE:' + message_id);
+ }
+ left_buttons.appendChild(accept_button);
+ var refuse_button = document.createElement('div');
+ refuse_button.innerHTML = refuseSvg;
+ refuse_button.setAttribute("id", "refuse-btn");
+ refuse_button.setAttribute("title", "Refuse");
+ refuse_button.setAttribute("class", "flat-button button-red");
+ refuse_button.onclick = function() {
+ window.prompt('REFUSE_FILE:' + message_id);
+ }
+ left_buttons.appendChild(refuse_button);
+ } else {
+ var status_button = document.createElement('div');
+ var statusFile = fileSvg;
+ if (isErrorStatus(message_delivery_status))
+ statusFile = warningSvg;
+ status_button.innerHTML = statusFile;
+ status_button.setAttribute("class", "flat-button");
+ left_buttons.appendChild(status_button);
+ var direction_button = document.createElement('div');
+ var directionFile = message_direction === 'out' ? outgoingSvg: incomingSvg;
+ direction_button.innerHTML = directionFile;
+ direction_button.setAttribute("class", "flat-button");
+ left_buttons.appendChild(direction_button);
+ }
+ updateProgressBar(chatview_message_transfer_progress_bar, message_object);
+ }
+
/**
* Adds a message to the buffer, or update it if new_message is
* TRUE
@@ -428,10 +541,10 @@
chatview_message_sender_span,
chatview_message_sender_image,
chatview_message_div,
- sentAnimation = "<svg overflow='visible' viewBox='0 -2 16 14' height='16px' width='16px'><path class='status-check' stroke='#008000' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' fill='none' d='M2,8 L6,12 L14,4'/></svg>",
- chatview_sentCheckmark = document.createElement('span');
+ sentAnimation = "<svg overflow='visible' viewBox='0 -2 16 14' height='16px' width='16px'><path class='status-check' stroke='#008000' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' fill='none' d='M2,8 L6,12 L14,4'/></svg>";
- chatview_sentCheckmark.setAttribute("class", "sent-checkmark");
+ var chatview_sentCheckmark = document.createElement('span');
+ chatview_sentCheckmark.setAttribute("class", "sent-checkmark");
chatview_message_div = document.querySelector("#message_" + message_id);
if (new_message)
@@ -449,32 +562,56 @@
chatview_message_wrapper = document.createElement('div');
chatview_message_wrapper.setAttribute("class", "message_wrapper wc");
- chatview_message_text = document.createElement('span');
- chatview_message_text.setAttribute("class", "message_text");
+ if (message_type === 'data_transfer') {
+ var leftbuttons_div = document.createElement('div');
+ leftbuttons_div.setAttribute("id", "left_buttons");
+ chatview_message_wrapper.appendChild(leftbuttons_div);
+
+ var text_div = document.createElement('div');
+ text_div.setAttribute("id", "text");
+ text_div.addEventListener('click', function (event) {
+ // ask the soft to open the file
+ var filename = document.querySelector("#message_" + message_id + " #filename").innerText;
+ window.prompt('OPEN_FILE:' + filename);
+ });
+ chatview_message_text = document.createElement('div');
+ chatview_message_text.setAttribute("id", "filename");
+ var informations_div = document.createElement('div');
+ informations_div.setAttribute("id", "informations");
+ text_div.appendChild(chatview_message_text);
+ text_div.appendChild(informations_div);
+ chatview_message_wrapper.appendChild(text_div);
+
+ // DataTransfer progress bar
+ chatview_message_transfer_progress_bar = document.createElement('span');
+ chatview_message_transfer_progress_bar.setAttribute("class", "message_progress_bar");
+ chatview_message_transfer_progress_completion = document.createElement('span');
+ chatview_message_transfer_progress_bar.appendChild(chatview_message_transfer_progress_completion);
+ chatview_message_wrapper.appendChild(chatview_message_transfer_progress_bar);
+ } else {
+ chatview_message_text = document.createElement('span');
+ chatview_message_text.setAttribute("class", "message_text");
+ chatview_message_wrapper.appendChild(chatview_message_text);
+ chatview_message_delivery_status = document.createElement('span');
+ chatview_message_delivery_status.setAttribute("class", "message_delivery_status");
+ }
+
chatview_message_sender = document.createElement('span');
chatview_message_sender.setAttribute("class", "message_sender");
-
- chatview_message_delivery_status = document.createElement('span');
- chatview_message_delivery_status.setAttribute("class", "message_delivery_status");
-
- chatview_message_timestamp = document.createElement('span');
- chatview_message_timestamp.setAttribute("class", "message_timestamp");
-
- chatview_message_wrapper.appendChild(chatview_message_text);
chatview_message_wrapper.appendChild(chatview_message_sender);
-
- // Sender image
chatview_message_sender_span = document.createElement('span');
chatview_message_sender_span.setAttribute("class", "message_sender_image");
-
chatview_message_sender_image = document.createElement('span');
chatview_message_sender_image.setAttribute("class", "sender_image sender_image_" + message_sender_contact_method);
+ chatview_message_timestamp = document.createElement('span');
+ chatview_message_timestamp.setAttribute("class", "message_timestamp");
// Append elements to div
chatview_message_div.appendChild(chatview_message_sender_image);
chatview_message_div.appendChild(chatview_message_wrapper);
- chatview_message_div.appendChild(chatview_message_delivery_status);
+ if (message_type !== 'data_transfer')
+ chatview_message_div.appendChild(chatview_message_delivery_status);
// Get timestamp to add
const formattedTimestamp = getMessageTimestampText(message_timestamp, true);
@@ -487,7 +624,7 @@
];
date_elt.setAttribute("class", timestamp_div_classes.join(" "));
date_elt.setAttribute("message_timestamp", message_timestamp);
- // Remove last timestamp if it's the same
+ // Remove last timestamp if it's the same<h6></h6>
if (messages.querySelectorAll(".timestamp"))
cleanPreviousTimestamps(date_elt, messages.children.length);
@@ -500,20 +637,17 @@
messages.insertBefore(chatview_message_div, messages.firstChild);
}
} else {
-
- chatview_message_div = document.querySelector("#message_" + message_id);
-
if (chatview_message_div) {
+ if (message_type === 'data_transfer') {
+ chatview_message_text = chatview_message_div.querySelector("#filename");
+ } else {
chatview_message_text = chatview_message_div.querySelector(".message_text");
- chatview_message_sender_image = chatview_message_div.querySelector(".message_sender_image");
- chatview_message_sender = chatview_message_div.querySelector(".message_sender");
chatview_message_delivery_status = chatview_message_div.querySelector(".message_delivery_status");
- chatview_message_timestamp = chatview_message_div.querySelector(".message_timestamp");
-
+ }
+ chatview_message_timestamp = chatview_message_div.querySelector(".message_timestamp");
+ chatview_message_sender = chatview_message_div.querySelector(".message_sender");
} else {
-
console.log('no msg selector.');
-
}
}
@@ -522,20 +656,25 @@
if (new_message && displayLinksEnabled)
displayLinks(chatview_message_text);
chatview_message_sender.textContent = message_sender + ": ";
- chatview_message_delivery_status.innerHTML = getMessageDeliveryStatusText(message_delivery_status);
chatview_message_timestamp.textContent = getMessageTimestampText(message_timestamp);
- if (new_message) {
- if (message_direction === "out") {
- chatview_sentCheckmark.innerHTML = sentAnimation;
- chatview_message_div.querySelector(".message_wrapper").appendChild(chatview_sentCheckmark);
- }
+ if (message_type === 'data_transfer') {
+ updateDataTransferInteraction(chatview_message_div, message_object);
+ } else {
+ chatview_message_delivery_status.innerHTML = getMessageDeliveryStatusText(message_delivery_status);
+ }
- chatview_message_div.querySelector(".message_wrapper").appendChild(chatview_message_timestamp);
+ // Add timestamp and sent checkmark
+ if (new_message) {
+ if (message_direction === "out") {
+ chatview_sentCheckmark.innerHTML = sentAnimation;
+ chatview_message_div.querySelector(".message_wrapper").appendChild(chatview_sentCheckmark);
+ }
+ chatview_message_div.querySelector(".message_wrapper").appendChild(chatview_message_timestamp);
}
if (message_direction === "out") {
- if (message_delivery_status === "sent") {
+ if (message_delivery_status === "sent" || message_delivery_status === "finished") {
chatview_message_div.classList.add("message--sent");
}
}
@@ -678,6 +817,11 @@
}
}
+ function sendFile()
+ {
+ window.prompt('SEND_FILE');
+ }
+
return {
addMessage: addMessage,
printHistory: printHistory,
@@ -696,6 +840,8 @@
showInvitation: showInvitation,
hideInvitation: hideInvitation,
disableSendMessage: disableSendMessage,
+ updateTimestamps: updateTimestamps,
+ sendFile: sendFile,
}
})();