summaryrefslogtreecommitdiff
path: root/addons/mail/static/src
diff options
context:
space:
mode:
authorAlexandre Kühn <aku@odoo.com>2018-12-05 14:35:02 +0000
committerAlexandre Kühn <aku@odoo.com>2018-12-06 14:51:28 +0000
commit7ad45a04e1a368f132fcc83bbe992ce0e98ed3d2 (patch)
tree5b106206817e1f73251374879f6d18d174704559 /addons/mail/static/src
parent9117d968e056d7c4e1112079e7e0ea0dd63cf9a5 (diff)
[IMP] im_livechat, mail: improved "is typing" notification
With this commit, the UI for "is typing..." notifications has changed. ** before **: In Discuss & chat windows, "is typing..." notification bar at the bottom of the thread, inside the conversation. ** after ** In chat windows, animated '...' next to conversation name. In Discuss, animated '...' next to conversation name in sidebar, and text below the composer. Task-ID 1881001
Diffstat (limited to 'addons/mail/static/src')
-rw-r--r--addons/mail/static/src/js/composers/basic_composer.js21
-rw-r--r--addons/mail/static/src/js/discuss.js28
-rw-r--r--addons/mail/static/src/js/models/threads/thread_typing_mixin/thread_typing_mixin.js9
-rw-r--r--addons/mail/static/src/js/services/mail_window_manager.js20
-rw-r--r--addons/mail/static/src/js/thread_widget.js28
-rw-r--r--addons/mail/static/src/js/thread_windows/abstract_thread_window.js18
-rw-r--r--addons/mail/static/src/js/thread_windows/thread_window.js17
-rw-r--r--addons/mail/static/src/scss/abstract_thread_window.scss12
-rw-r--r--addons/mail/static/src/scss/composer.scss5
-rw-r--r--addons/mail/static/src/scss/discuss.scss7
-rw-r--r--addons/mail/static/src/scss/thread.scss57
-rw-r--r--addons/mail/static/src/xml/abstract_thread_window.xml3
-rw-r--r--addons/mail/static/src/xml/composer.xml8
-rw-r--r--addons/mail/static/src/xml/discuss.xml4
-rw-r--r--addons/mail/static/src/xml/thread.xml28
15 files changed, 149 insertions, 116 deletions
diff --git a/addons/mail/static/src/js/composers/basic_composer.js b/addons/mail/static/src/js/composers/basic_composer.js
index c8f7d702af4..1a40e3f48fa 100644
--- a/addons/mail/static/src/js/composers/basic_composer.js
+++ b/addons/mail/static/src/js/composers/basic_composer.js
@@ -123,6 +123,9 @@ var BasicComposer = Widget.extend({
$(window).on(this.fileuploadID, this._onAttachmentLoaded.bind(this));
this.on('change:attachment_ids', this, this._renderAttachments);
+ this.call('mail_service', 'getMailBus')
+ .on('update_typing_partners', this, this._onUpdateTypingPartners);
+
// Mention
this._mentionManager.prependTo(this.$('.o_composer'));
@@ -793,6 +796,24 @@ var BasicComposer = Widget.extend({
this._mentionManager.detectDelimiter();
}
},
+ /**
+ * @private
+ * @param {integer|string} threadID
+ */
+ _onUpdateTypingPartners: function (threadID) {
+ if (!this.options.showTyping) {
+ return;
+ }
+ if (!this.options.thread) {
+ return;
+ }
+ if (this.options.thread.getID() !== threadID) {
+ return;
+ }
+ this.$('.o_composer_thread_typing').html(QWeb.render('mail.Composer.ThreadTyping', {
+ thread: this.options.thread,
+ }));
+ },
});
return BasicComposer;
diff --git a/addons/mail/static/src/js/discuss.js b/addons/mail/static/src/js/discuss.js
index 2cb9fe749d7..dd03f08028c 100644
--- a/addons/mail/static/src/js/discuss.js
+++ b/addons/mail/static/src/js/discuss.js
@@ -235,12 +235,14 @@ var Discuss = AbstractAction.extend(ControlPanelMixin, {
start: function () {
var self = this;
- this._basicComposer = new BasicComposer(this,
- { mentionPartnersRestricted: true }
- );
- this._extendedComposer = new ExtendedComposer(this,
- { mentionPartnersRestricted: true }
- );
+ this._basicComposer = new BasicComposer(this, {
+ mentionPartnersRestricted: true,
+ showTyping: true,
+ });
+ this._extendedComposer = new ExtendedComposer(this, {
+ mentionPartnersRestricted: true,
+ showTyping: true,
+ });
this._basicComposer
.on('post_message', this, this._onPostMessage)
.on('input_focused', this, this._onComposerFocused);
@@ -1391,19 +1393,9 @@ var Discuss = AbstractAction.extend(ControlPanelMixin, {
},
/**
* @private
- * @param {integer|string} threadID
*/
- _onTypingPartnersUpdated: function (threadID) {
- var self = this;
- if (this._thread.getID() !== threadID) {
- return;
- }
- if (this._thread.hasTypingNotification()) {
- // call getMentionpartnerSuggestions in order to correctly fetch members
- this._thread.getMentionPartnerSuggestions().then(function () {
- self._threadWidget.renderTypingNotificationBar(self._thread);
- });
- }
+ _onTypingPartnersUpdated: function () {
+ this._updateThreads();
},
/**
* @private
diff --git a/addons/mail/static/src/js/models/threads/thread_typing_mixin/thread_typing_mixin.js b/addons/mail/static/src/js/models/threads/thread_typing_mixin/thread_typing_mixin.js
index fb1a3a91cd1..9a5b5abb4cc 100644
--- a/addons/mail/static/src/js/models/threads/thread_typing_mixin/thread_typing_mixin.js
+++ b/addons/mail/static/src/js/models/threads/thread_typing_mixin/thread_typing_mixin.js
@@ -148,6 +148,15 @@ var ThreadTypingMixin = {
return true;
},
/**
+ * Tells if someone other than current user is typing something on this
+ * thread.
+ *
+ * @returns {boolean}
+ */
+ isSomeoneTyping: function () {
+ return !(_.isEmpty(this._typingPartnerIDs));
+ },
+ /**
* Register someone that is currently typing something in this thread.
* If this is the current user that is typing something, don't do anything
* (we do not have to display anything)
diff --git a/addons/mail/static/src/js/services/mail_window_manager.js b/addons/mail/static/src/js/services/mail_window_manager.js
index 79ea668e55e..64cf6bb88c9 100644
--- a/addons/mail/static/src/js/services/mail_window_manager.js
+++ b/addons/mail/static/src/js/services/mail_window_manager.js
@@ -329,8 +329,7 @@ MailManager.include({
.on('is_thread_bottom_visible', this, this._onIsThreadBottomVisible)
.on('unsubscribe_from_channel', this, this._onUnsubscribeFromChannel)
.on('update_thread_unread_counter', this, this._onUpdateThreadUnreadCounter)
- .on('update_dm_presence', this, this._onUpdateDmPresence)
- .on('update_typing_partners', this, this._onTypingPartnersUpdated);
+ .on('update_dm_presence', this, this._onUpdateDmPresence);
core.bus.on('resize', this, _.debounce(this._repositionThreadWindows.bind(this), 100));
},
@@ -656,23 +655,6 @@ MailManager.include({
this._updateThreadWindowsFromMessage(message, { keepBottom: true, passively: true });
},
/**
- * @private
- * @param {integer|string} threadID
- */
- _onTypingPartnersUpdated: function (threadID) {
- var threadWindow = this._getThreadWindow(threadID);
- if (!threadWindow) {
- return;
- }
- var thread = this.getThread(threadID);
- if (thread.isChannel()) {
- // call getMentionpartnerSuggestions in order to correctly fetch members
- thread.getMentionPartnerSuggestions().then(function () {
- threadWindow.renderTypingNotificationBar();
- });
- }
- },
- /**
* Close the thread window when unsusbscribe from a channel.
*
* @private
diff --git a/addons/mail/static/src/js/thread_widget.js b/addons/mail/static/src/js/thread_widget.js
index e6da87c6dba..da74028903e 100644
--- a/addons/mail/static/src/js/thread_widget.js
+++ b/addons/mail/static/src/js/thread_widget.js
@@ -185,12 +185,6 @@ var ThreadWidget = Widget.extend({
dateFormat: time.getLangDatetimeFormat(),
}));
- // must be after mail.widget.Thread rendering, so that there is the
- // DOM element for the 'is typing' notification bar
- if (thread.hasTypingNotification()) {
- this.renderTypingNotificationBar(thread);
- }
-
_.each(messages, function (message) {
var $message = self.$('.o_thread_message[data-message-id="'+ message.getID() +'"]');
$message.find('.o_mail_timestamp').data('date', message.getDate());
@@ -254,28 +248,6 @@ var ThreadWidget = Widget.extend({
return done;
},
/**
- * Render the 'is typing...' text on the typing notification bar of the
- * thread. This is called when there is a change in the list of users
- * typing something on this thread.
- *
- * @param {mail.model.AbstractThread} thread with ThreadTypingMixin
- */
- renderTypingNotificationBar: function (thread) {
- if (this._currentThreadID === thread.getID()) {
- var shouldScrollToBottomAfterRendering = this.isAtBottom();
-
- // typing notification bar rendering
- var $typingBar = this.$('.o_thread_typing_notification_bar');
- var text = thread.getTypingMembersToText();
- $typingBar.toggleClass('o_hidden', !text); // hide if no text, because of padding
- $typingBar.text(text);
-
- if (shouldScrollToBottomAfterRendering) {
- this.scrollToBottom();
- }
- }
- },
- /**
* Scroll to the bottom of the thread
*/
scrollToBottom: function () {
diff --git a/addons/mail/static/src/js/thread_windows/abstract_thread_window.js b/addons/mail/static/src/js/thread_windows/abstract_thread_window.js
index f4bf9533ff9..3e4e2e16325 100644
--- a/addons/mail/static/src/js/thread_windows/abstract_thread_window.js
+++ b/addons/mail/static/src/js/thread_windows/abstract_thread_window.js
@@ -139,6 +139,15 @@ var AbstractThreadWindow = Widget.extend({
return this._getThreadID();
},
/**
+ * @returns {mail.model.Thread|undefined}
+ */
+ getThread: function () {
+ if (!this.hasThread) {
+ return undefined;
+ }
+ return this._thread;
+ },
+ /**
* Get the status of the thread, such as the im status of a DM chat
* ('online', 'offline', etc.). If this window has no thread, returns
* `undefined`.
@@ -257,14 +266,6 @@ var AbstractThreadWindow = Widget.extend({
QWeb.render('mail.AbstractThreadWindow.HeaderContent', options));
},
/**
- * Render the 'is typing...' notification bar text on the thread in this
- * thread window. This is called when there is a change in the list of users
- * currently typing something on this thread.
- */
- renderTypingNotificationBar: function () {
- this._threadWidget.renderTypingNotificationBar(this._thread);
- },
- /**
* Scroll to the bottom of the thread in the thread window
*/
scrollToBottom: function () {
@@ -339,6 +340,7 @@ var AbstractThreadWindow = Widget.extend({
_getHeaderRenderingOptions: function () {
return {
status: this.getThreadStatus(),
+ thread: this.getThread(),
title: this.getTitle(),
unreadCounter: this.getUnreadCounter(),
widget: this,
diff --git a/addons/mail/static/src/js/thread_windows/thread_window.js b/addons/mail/static/src/js/thread_windows/thread_window.js
index 62468e9ea16..f4b0137c476 100644
--- a/addons/mail/static/src/js/thread_windows/thread_window.js
+++ b/addons/mail/static/src/js/thread_windows/thread_window.js
@@ -55,6 +55,9 @@ var ThreadWindow = AbstractThreadWindow.extend({
var superDef = this._super().then(this._listenThreadWidget.bind(this));
+ this.call('mail_service', 'getMailBus')
+ .on('update_typing_partners', this, this._onUpdateTypingPartners);
+
var composerDef;
if (!this.hasThread()) {
this._startWithoutThread();
@@ -353,7 +356,19 @@ var ThreadWindow = AbstractThreadWindow.extend({
var message = this.call('mail_service', 'getMessage', messageID);
message.toggleStarStatus();
},
-
+ /**
+ * @private
+ * @param {integer|string} threadID
+ */
+ _onUpdateTypingPartners: function (threadID) {
+ if (!this.hasThread()) {
+ return;
+ }
+ if (this._thread.getID() !== threadID) {
+ return;
+ }
+ this.renderHeader();
+ },
});
return ThreadWindow;
diff --git a/addons/mail/static/src/scss/abstract_thread_window.scss b/addons/mail/static/src/scss/abstract_thread_window.scss
index a4ad6d366cc..b148afa111f 100644
--- a/addons/mail/static/src/scss/abstract_thread_window.scss
+++ b/addons/mail/static/src/scss/abstract_thread_window.scss
@@ -57,6 +57,14 @@ $o-mail-thread-window-zindex: $zindex-modal + 1 !default;
cursor: pointer;
flex: 1 1 auto;
@include o-text-overflow;
+
+ .o_mail_thread_typing_icon {
+ padding-left: 2px;
+
+ .o_mail_thread_typing_icon_dot {
+ background: gray('300');
+ }
+ }
}
.o_thread_window_buttons {
@@ -76,10 +84,6 @@ $o-mail-thread-window-zindex: $zindex-modal + 1 !default;
overflow: auto;
-webkit-overflow-scrolling: touch; // smooth scrolling in iOS app (Safari)
- .o_thread_typing_notification_bar {
- background-color: rgba($o-mail-thread-window-bg, 0.75);
- }
-
.o_thread_date_separator {
margin: 0px 0px 15px 0px;
.o_thread_date {
diff --git a/addons/mail/static/src/scss/composer.scss b/addons/mail/static/src/scss/composer.scss
index e076629f667..f12e195abe9 100644
--- a/addons/mail/static/src/scss/composer.scss
+++ b/addons/mail/static/src/scss/composer.scss
@@ -184,6 +184,11 @@
flex: 1 0 100%;
}
+ .o_composer_thread_typing {
+ font-size: 0.9em;
+ color: gray('600');
+ }
+
.o_chatter_composer_tools {
border: none;
border-left: 1px solid gray('300');
diff --git a/addons/mail/static/src/scss/discuss.scss b/addons/mail/static/src/scss/discuss.scss
index 8d328b028bf..39c30aefa05 100644
--- a/addons/mail/static/src/scss/discuss.scss
+++ b/addons/mail/static/src/scss/discuss.scss
@@ -44,6 +44,9 @@
flex: 1 1 auto;
@include o-text-overflow;
}
+ .o_mail_thread_typing_icon_dot {
+ background: gray('600');;
+ }
.o_mail_sidebar_needaction, .o_mail_partner_unpin, .o_mail_channel_settings {
flex: 0 0 auto;
}
@@ -129,7 +132,7 @@
background-color: darken(gray('900'),2%);
.o_mail_partner_unpin, .o_mail_channel_settings {
- opacity: $o-mail-sidebar-icon-opacity;
+ display: inline-block;
}
}
@@ -143,7 +146,7 @@
}
.o_mail_partner_unpin, .o_mail_channel_settings {
- @include o-hover-opacity($default-opacity: 0, $hover-opacity: 1);
+ display: none;
}
&.o_unread_message {
color: white;
diff --git a/addons/mail/static/src/scss/thread.scss b/addons/mail/static/src/scss/thread.scss
index 81f6862ca9f..a56f54bad78 100644
--- a/addons/mail/static/src/scss/thread.scss
+++ b/addons/mail/static/src/scss/thread.scss
@@ -13,26 +13,6 @@
height: 15px;
}
- .o_thread_typing_notification_free_space {
- flex-grow: 1,
- }
-
- .o_thread_typing_notification_bar {
- flex: 0, 0, 20px;
- background-color: rgba($white, 0.75);
- padding: 5px;
- text-align: center;
- color: gray('600');
-
- &.o_thread_order_asc {
- @include o-position-sticky($bottom: 0px);
- }
-
- &.o_thread_order_desc {
- @include o-position-sticky($top: 0px);
- }
- }
-
.o_thread_tooltip_container {
display: inline;
position: relative;
@@ -239,3 +219,40 @@
opacity: $o-mail-thread-icon-opacity;
}
}
+
+// ------------------------------------------------------------------
+// Thread typing icon: shared between discuss and chat windows
+// ------------------------------------------------------------------
+
+.o_mail_thread_typing_icon {
+ position: relative;
+ text-align: center;
+ margin-left: auto;
+ margin-right: auto;
+
+ .o_mail_thread_typing_icon_dot {
+ display: inline-block;
+ width: 3px;
+ height: 3px;
+ border-radius: 50%;
+ background: gray('800');
+ animation: o_mail_thread_typing_icon_dot 1.5s linear infinite;
+
+ &:nth-child(2) {
+ animation-delay: -1.35s;
+ }
+
+ &:nth-child(3) {
+ animation-delay: -1.2s;
+ }
+ }
+}
+
+@keyframes o_mail_thread_typing_icon_dot {
+ 0%, 40%, 100% {
+ transform: initial;
+ }
+ 20% {
+ transform: translateY(-5px);
+ }
+}
diff --git a/addons/mail/static/src/xml/abstract_thread_window.xml b/addons/mail/static/src/xml/abstract_thread_window.xml
index de0418af3df..89c45323c7a 100644
--- a/addons/mail/static/src/xml/abstract_thread_window.xml
+++ b/addons/mail/static/src/xml/abstract_thread_window.xml
@@ -11,6 +11,7 @@
<t t-set="status" t-value="widget.getThreadStatus()"/>
<t t-set="title" t-value="widget.getTitle()"/>
<t t-set="unreadCounter" t-value="widget.getUnreadCounter()"/>
+ <t t-set="thread" t-value="widget.getThread()"/>
</t>
</div>
<div class="o_thread_window_content">
@@ -58,6 +59,7 @@
name of the document.
@param {integer} [unreadCounter] the number of unread messages on the
thread.
+ @param {mail.model.Thread|undefined} thread
@param {Object} widget
@param {function} widget.isMobile function without any param that
states whether it should render for desktop or mobile screen.
@@ -70,6 +72,7 @@
<t t-if="status" t-call="mail.UserStatus"/>
<t t-esc="title"/>
<span t-if="unreadCounter"> (<t t-esc="unreadCounter"/>)</span>
+ <t t-if="thread and thread.hasTypingNotification() and thread.isSomeoneTyping()" t-call="mail.ThreadTypingIcon"/>
</span>
<span t-if="!widget.isMobile()" class="o_thread_window_buttons">
<a href="#" class="o_thread_window_close fa fa-close"/>
diff --git a/addons/mail/static/src/xml/composer.xml b/addons/mail/static/src/xml/composer.xml
index 883c9752035..6147197cd17 100644
--- a/addons/mail/static/src/xml/composer.xml
+++ b/addons/mail/static/src/xml/composer.xml
@@ -24,6 +24,7 @@
</div>
</div>
<div class="o_composer_attachments_list"/>
+ <div class="o_composer_thread_typing"/>
</div>
<div class="o_composer_send">
<button tabindex="3" class="btn btn-primary o_composer_button_send d-none d-md-inline-block" type="button"><t t-esc="widget.options.sendText"/></button>
@@ -40,6 +41,13 @@
</span>
</div>
+ <!--
+ @param {mail.model.Thread} thread
+ -->
+ <t t-name="mail.Composer.ThreadTyping">
+ <t t-esc="thread.getTypingMembersToText()"/>
+ </t>
+
<div t-name="mail.Composer.emojis" class="o_mail_emoji_container">
<t t-foreach="emojis" t-as="emoji">
<button t-att-data-emoji="emoji.sources[0]" class="btn btn-link o_mail_emoji" t-att-title="emoji.description" t-att-aria-label="emoji.description">
diff --git a/addons/mail/static/src/xml/discuss.xml b/addons/mail/static/src/xml/discuss.xml
index 605dcb53956..f97e38768e4 100644
--- a/addons/mail/static/src/xml/discuss.xml
+++ b/addons/mail/static/src/xml/discuss.xml
@@ -140,6 +140,10 @@
<t t-esc="_.unescape(thread.getName())"/>
<i t-if="thread.isMassMailing()" class="fa fa-envelope-o" title="Sends messages by email" role="img" aria-label="Send by mail"/>
</span>
+ <t t-if="channel.hasTypingNotification() and channel.isSomeoneTyping()">
+ <t t-set="thread" t-value="channel"/>
+ <t t-call="mail.ThreadTypingIcon"/>
+ </t>
<span t-attf-class="fa fa-cog o_mail_channel_settings"
title="Channel settings" role="img" aria-label="Channel settings" t-att-data-thread-id="thread.getID()"/>
<t t-call="mail.discuss.SidebarCounter"/>
diff --git a/addons/mail/static/src/xml/thread.xml b/addons/mail/static/src/xml/thread.xml
index f28e071b2f3..a1e2d52e2ad 100644
--- a/addons/mail/static/src/xml/thread.xml
+++ b/addons/mail/static/src/xml/thread.xml
@@ -191,7 +191,6 @@
<t t-if="options.displayBottomThreadFreeSpace">
<div class="o_thread_bottom_free_space"/>
</t>
- <t t-if="thread.hasTypingNotification()" t-call="mail.widget.Thread.TypingNotificationBar"/>
</div>
</t>
@@ -217,27 +216,12 @@
<div class="o_mail_thread_content">
<t t-if="options.messagesSeparatorPosition == 'top'" t-call="mail.MessagesSeparator"/>
<t t-set="messages" t-value="messages.slice().reverse()"/>
- <t t-if="thread.hasTypingNotification()" t-call="mail.widget.Thread.TypingNotificationBar"/>
<t t-call="mail.widget.Thread.Messages"/>
<t t-if="options.displayLoadMore" t-call="mail.widget.Thread.LoadMore"/>
</div>
</t>
<!--
- @param {mail.model.AbstractThread} thread
- -->
- <t t-name="mail.widget.Thread.TypingNotificationBar">
- <t t-if="options.displayOrder === ORDER.ASC">
- <div class="o_thread_typing_notification_free_space"/>
- <div class="o_thread_typing_notification_bar o_thread_order_asc"/>
- </t>
- <t t-else="">
- <div class="o_thread_typing_notification_free_space"/>
- <div class="o_thread_typing_notification_bar o_thread_order_desc"/>
- </t>
- </t>
-
- <!--
@param {mail.model.AbstractMessage[]} messages messages are ordered based
on desired display order
-->
@@ -550,4 +534,16 @@
</t>
</div>
</t>
+
+ <!--
+ @param {mail.model.Thread} thread with typing feature
+ -->
+ <t t-name="mail.ThreadTypingIcon">
+ <span class="o_mail_thread_typing_icon" t-att-title="thread.getTypingMembersToText()">
+ <span class="o_mail_thread_typing_icon_dot"/>
+ <span class="o_mail_thread_typing_icon_dot"/>
+ <span class="o_mail_thread_typing_icon_dot"/>
+ </span>
+ </t>
+
</templates>