Commit b425324d authored by Sébastien Blin's avatar Sébastien Blin

chatview: improve UI for text input

Move current message input in the webview and improve the UI.

Change-Id: Iae2d9406358b80404d21fb9183614cfb306a0ff6
parent 436bd9bd
<svg fill="#000000" height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg">
<path d="M0 0h24v24H0z" fill="none"/>
<path d="M6.62 10.79c1.44 2.83 3.76 5.14 6.59 6.59l2.2-2.2c.27-.27.67-.36 1.02-.24 1.12.37 2.33.57 3.57.57.55 0 1 .45 1 1V20c0 .55-.45 1-1 1-9.39 0-17-7.61-17-17 0-.55.45-1 1-1h3.5c.55 0 1 .45 1 1 0 1.25.2 2.45.57 3.57.11.35.03.74-.25 1.02l-2.2 2.2z"/>
</svg>
\ No newline at end of file
<svg fill="#000000" height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg">
<path d="M0 0h24v24H0z" fill="none"/>
<path d="M15 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm-9-2V7H4v3H1v2h3v3h2v-3h3v-2H6zm9 4c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z"/>
</svg>
\ No newline at end of file
......@@ -4,11 +4,12 @@
<file alias="ring-symbol-blue">ring.svg</file>
<file alias="ring-logo-blue">logo-ring-standard-coul.svg</file>
<file alias="addressbook_small">addressbook.svg</file>
<file alias="history_small">history.svg</file>
<file alias="history_small">history.svg</file>
<file alias="clear_history">ic_delete_forever_black_24px.svg</file>
<file alias="users_small">users.svg</file>
<file alias="dial">dial.svg</file>
<file alias="call">call.svg</file>
<file alias="call">call.svg</file>
<file alias="call_start">ic_call_black_24px.svg</file>
<file alias="contact">contact.svg</file>
<file alias="accept">accept.svg</file>
<file alias="reject">hang_up.svg</file>
......@@ -23,7 +24,8 @@
<file alias="contact_requests_list">ic_verified_user_black_24px.svg</file>
<file alias="history_list">ic_history_black_24px.svg</file>
<file alias="block">ic_block_black_24px.svg</file>
<file alias="add">ic_add_black_24px.svg</file>
<file alias="add">ic_add_black_24px.svg</file>
<file alias="invite">ic_person_add_black_24px.svg</file>
<file alias="contact_requests_list_with_notification">ic_verified_user_black_24px_with_notification.svg</file>
</gresource>
</gresources>
......@@ -58,8 +58,6 @@ struct _ChatViewPrivate
{
GtkWidget *box_webkit_chat_container;
GtkWidget *webkit_chat_container;
GtkWidget *button_chat_input;
GtkWidget *entry_chat_input;
GtkWidget *scrolledwindow_chat;
GtkWidget *hbox_chat_info;
GtkWidget *label_peer;
......@@ -80,6 +78,7 @@ struct _ChatViewPrivate
QMetaObject::Connection update_name;
gulong webkit_ready;
gulong webkit_send_text;
};
G_DEFINE_TYPE_WITH_PRIVATE(ChatView, chat_view, GTK_TYPE_BOX);
......@@ -113,6 +112,8 @@ chat_view_dispose(GObject *object)
/* disconnect for webkit signals */
g_signal_handler_disconnect(priv->webkit_chat_container, priv->webkit_ready);
priv->webkit_ready = 0;
g_signal_handler_disconnect(priv->webkit_chat_container, priv->webkit_send_text);
priv->webkit_send_text = 0;
gtk_container_remove(
GTK_CONTAINER(priv->box_webkit_chat_container),
......@@ -125,44 +126,6 @@ chat_view_dispose(GObject *object)
G_OBJECT_CLASS(chat_view_parent_class)->dispose(object);
}
static void
send_chat(G_GNUC_UNUSED GtkWidget *widget, ChatView *self)
{
g_return_if_fail(IS_CHAT_VIEW(self));
ChatViewPrivate *priv = CHAT_VIEW_GET_PRIVATE(self);
/* make sure there is more than just whitespace, but if so, send the original text */
const auto text = QString(gtk_entry_get_text(GTK_ENTRY(priv->entry_chat_input)));
if (!text.trimmed().isEmpty()) {
QMap<QString, QString> messages;
messages["text/plain"] = text;
if (priv->call) {
// in call message
priv->call->addOutgoingMedia<Media::Text>()->send(messages);
} else if (priv->person) {
// get the chosen cm
auto active = gtk_combo_box_get_active(GTK_COMBO_BOX(priv->combobox_cm));
if (active >= 0) {
auto cm = priv->person->phoneNumbers().at(active);
if (!cm->sendOfflineTextMessage(messages))
g_warning("message failed to send"); // TODO: warn the user about this in the UI
} else {
g_warning("no ContactMethod chosen; message not sent");
}
} else if (priv->cm) {
if (!priv->cm->sendOfflineTextMessage(messages))
g_warning("message failed to send"); // TODO: warn the user about this in the UI
} else {
g_warning("no Call, Person, or ContactMethod set; message not sent");
}
/* clear the entry */
gtk_entry_set_text(GTK_ENTRY(priv->entry_chat_input), "");
}
}
static void
hide_chat_view(G_GNUC_UNUSED GtkWidget *widget, ChatView *self)
{
......@@ -229,6 +192,39 @@ button_send_invitation_clicked(ChatView *self)
// TODO : add an entry in the conversation to tell the user an invitation was sent.
}
static void
webkit_chat_container_send_text(G_GNUC_UNUSED GtkWidget* webview, gchar *message, ChatView* self)
{
ChatViewPrivate *priv = CHAT_VIEW_GET_PRIVATE(self);
/* make sure there is more than just whitespace, but if so, send the original text */
const auto text = QString(message);
if (!text.trimmed().isEmpty()) {
QMap<QString, QString> messages;
messages["text/plain"] = text;
if (priv->call) {
// in call message
priv->call->addOutgoingMedia<Media::Text>()->send(messages);
} else if (priv->person) {
// get the chosen cm
auto active = gtk_combo_box_get_active(GTK_COMBO_BOX(priv->combobox_cm));
if (active >= 0) {
auto cm = priv->person->phoneNumbers().at(active);
if (!cm->sendOfflineTextMessage(messages))
g_warning("message failed to send"); // TODO: warn the user about this in the UI
} else {
g_warning("no ContactMethod chosen; message not sent");
}
} else if (priv->cm) {
if (!priv->cm->sendOfflineTextMessage(messages))
g_warning("message failed to send"); // TODO: warn the user about this in the UI
} else {
g_warning("no Call, Person, or ContactMethod set; message not sent");
}
}
}
static void
chat_view_init(ChatView *view)
{
......@@ -236,8 +232,6 @@ chat_view_init(ChatView *view)
ChatViewPrivate *priv = CHAT_VIEW_GET_PRIVATE(view);
g_signal_connect(priv->button_chat_input, "clicked", G_CALLBACK(send_chat), view);
g_signal_connect(priv->entry_chat_input, "activate", G_CALLBACK(send_chat), view);
g_signal_connect(priv->button_close_chatview, "clicked", G_CALLBACK(hide_chat_view), view);
g_signal_connect_swapped(priv->button_placecall, "clicked", G_CALLBACK(placecall_clicked), view);
g_signal_connect_swapped(priv->button_send_invitation, "clicked", G_CALLBACK(button_send_invitation_clicked), view);
......@@ -252,8 +246,6 @@ chat_view_class_init(ChatViewClass *klass)
"/cx/ring/RingGnome/chatview.ui");
gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), ChatView, box_webkit_chat_container);
gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), ChatView, button_chat_input);
gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), ChatView, entry_chat_input);
gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), ChatView, scrolledwindow_chat);
gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), ChatView, hbox_chat_info);
gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS (klass), ChatView, label_peer);
......@@ -620,6 +612,11 @@ build_chat_view(ChatView* self)
self
);
priv->webkit_send_text = g_signal_connect(priv->webkit_chat_container,
"send-message",
G_CALLBACK(webkit_chat_container_send_text),
self);
if (webkit_chat_container_is_ready(WEBKIT_CHAT_CONTAINER(priv->webkit_chat_container)))
webkit_chat_container_ready(self);
......
......@@ -68,6 +68,7 @@ G_DEFINE_TYPE_WITH_PRIVATE(WebKitChatContainer, webkit_chat_container, GTK_TYPE_
/* signals */
enum {
READY,
SEND_MESSAGE,
LAST_SIGNAL
};
......@@ -107,6 +108,15 @@ webkit_chat_container_class_init(WebKitChatContainerClass *klass)
nullptr,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0);
webkit_chat_container_signals[SEND_MESSAGE] = g_signal_new("send-message",
G_TYPE_FROM_CLASS(klass),
(GSignalFlags) (G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED),
0,
nullptr,
nullptr,
g_cclosure_marshal_VOID__STRING,
G_TYPE_NONE, 1, G_TYPE_STRING);
}
static gboolean
......@@ -238,6 +248,16 @@ webview_chat_decide_policy (G_GNUC_UNUSED WebKitWebView *web_view,
}
#endif
static gboolean
webview_send_text(WebKitWebView *self,
WebKitScriptDialog *dialog,
gpointer user_data)
{
auto message = webkit_script_dialog_get_message(dialog);
g_signal_emit(G_OBJECT(self), webkit_chat_container_signals[SEND_MESSAGE], 0, message);
return true;
}
static void
javascript_library_loaded(WebKitWebView *webview_chat,
GAsyncResult *result,
......@@ -392,6 +412,7 @@ build_view(WebKitChatContainer *view)
g_signal_connect(priv->webview_chat, "load-changed", G_CALLBACK(webview_chat_load_changed), view);
g_signal_connect_swapped(priv->webview_chat, "context-menu", G_CALLBACK(webview_chat_context_menu), view);
g_signal_connect_swapped(priv->webview_chat, "script-dialog", G_CALLBACK(webview_send_text), view);
#if WEBKIT_CHECK_VERSION(2, 6, 0)
g_signal_connect(priv->webview_chat, "decide-policy", G_CALLBACK(webview_chat_decide_policy), view);
#endif
......
......@@ -56,7 +56,7 @@
<child>
<object class="GtkButton" id="button_send_invitation">
<property name="visible">True</property>
<property name="label">Invite</property>
<property name="image">image_invite</property>
<property name="tooltip-text" translatable="yes">Send invitation</property>
</object>
<packing>
......@@ -102,42 +102,24 @@
</child>
<!-- end of chat text view -->
<!-- start of chat entry -->
<child>
<object class="GtkBox" id="hbox_chat_input">
<property name="visible">True</property>
<property name="orientation">horizontal</property>
<child>
<object class="GtkEntry" id="entry_chat_input">
<property name="visible">True</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
</packing>
</child>
<child>
<object class="GtkButton" id="button_chat_input">
<property name="visible">True</property>
<property name="label" translatable="yes">Send</property>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
</packing>
</child>
<!-- end of chat entry -->
</template>
<object class="GtkImage" id="image_back_arrow">
<property name="visible">True</property>
<property name="icon-name">go-previous-symbolic</property>
</object>
<object class="GtkImage" id="image_invite">
<property name="visible">True</property>
<property name="resource">/cx/ring/RingGnome/invite</property>
<child internal-child="accessible">
<object class="AtkObject" id="image_invite-atkobject">
<property name="AtkObject::accessible-description" translatable="yes">Send Invitation</property>
</object>
</child>
</object>
<object class="GtkImage" id="image_place_call">
<property name="visible">True</property>
<property name="icon-name">call-start-symbolic</property>
<property name="resource">/cx/ring/RingGnome/call_start</property>
</object>
</interface>
body {
margin: 0;
overflow: hidden;
}
#container {
position: relative;
height: 100%;
width: 100%;
display: flex;
flex-direction: column;
margin: 0;
padding: 0;
vertical-align: baseline;
}
#messages {
position: absolute;
bottom: 0;
left: 0;
max-height: 100%;
position: relative;
flex: 1;
z-index: 0;
width: 100%;
overflow-y: scroll;
height: auto;
}
#sendMessage {
display: flex;
width: 97%;
position: relative;
z-index: 1;
transform: translateZ(0);
height: auto;
border-top : 2px solid #d3d3d3;
padding-right: 10px;
margin-left: 1%;
margin-right: 1.5%;
}
#message {
width: 100%;
border: 0;
height: 55px;
overflow: hidden;
padding-right: 20px;
color: black;
padding-left: 8px;
}
#message:focus,
#message.focus {
border: 0;
outline: none;
}
input[placeholder], [placeholder], *[placeholder] {
color: #d3d3d3;
}
#sendBtn {
border-radius: 50%;
border: 0;
width: 40px;
height: 40px;
margin-top: 8px;
transition: all 0.3s ease;
}
#sendBtn.hover,
#sendBtn:hover {
background: #bae5f0;
}
#sendBtn.hover svg,
#sendBtn:hover svg {
fill: black;
}
#sendMessage svg {
fill: #666;
padding: 5px;
width: 100%;
height: 100%;
transition: all 0.3s ease;
}
.wc {
will-change: transform;
}
......@@ -172,8 +239,7 @@ body {
}
.message_out > .message_wrapper {
background-color: #00BFD3;
color: #fff;
background-color: #cfebf5;
border-top-right-radius: 0;
transform-origin: top right;
}
......@@ -258,7 +324,7 @@ body {
position: absolute;
right: -10px;
top: 0;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 10'%3E %3Cpath d= 'M0,0 L10,0 C0,0 0,10 0,10' fill='%2300BFD3'/%3E %3C/svg%3E");
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 10'%3E %3Cpath d= 'M0,0 L10,0 C0,0 0,10 0,10' fill='%23cfebf5'/%3E %3C/svg%3E");
transform-origin: top right;
}
......
......@@ -8,6 +8,17 @@
<body>
<div id="container">
<div id="messages"></div>
<div id="sendMessage">
<input id="message" type="text" autofocus placeholder="Message" onkeyup="auto_grow(this)"
onkeydown="if (event.keyCode == 13) { ring.chatview.sendMessage(); return false; }">
<div id="sendBtn" 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>
</form>
</div>
</body>
......@@ -26,6 +37,19 @@ ring.chatview = (function(){
var raf = window.requestAnimationFrame || window.webkitRequestAnimationFrame;
var messages = document.querySelector("#messages");
/**
* Send #sendMessage #message value
*/
function sendMessage()
{
var input = document.querySelector("#sendMessage #message");
var message = input.value;
if (message.length > 0) {
input.value = "";
window.prompt(message);
}
}
/**
* Clears all messages
*/
......@@ -276,6 +300,15 @@ ring.chatview = (function(){
document.head.appendChild(style);
}
/**
* Change the send icon
*/
function setSendIcon(source)
{
var sendBtn = document.querySelector("#sendicon");
sendBtn.src = "data:image/png;base64," + source;
}
function clearSenderImages()
{
var styles = document.head.querySelectorAll("style"),
......@@ -290,9 +323,11 @@ ring.chatview = (function(){
addMessage: addMessage,
updateMessage: updateMessage,
setSenderImage: setSenderImage,
setSendIcon: setSendIcon,
dev: dev,
clearMessages: clearMessages,
clearSenderImages: clearSenderImages,
sendMessage: sendMessage,
}
})();
......
Markdown is supported
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