Skip to content
Permalink
Browse files

[WIP] mail: chat window manager

  • Loading branch information...
alexkuhn committed May 13, 2019
1 parent 0358b2d commit f2f15cc2a8cd1fb7f84a08387a24675d423484e5
Showing with 1,667 additions and 981 deletions.
  1. +6 −0 addons/mail/__manifest__.py
  2. +0 −1 addons/mail/static/src/js/wip/old_widget/discuss.js
  3. +42 −14 addons/mail/static/src/js/wip/service/chat_window_service.js
  4. +16 −4 addons/mail/static/src/js/wip/service/store_service.js
  5. +15 −7 addons/mail/static/src/js/wip/store/actions.js
  6. +22 −0 addons/mail/static/src/js/wip/store/mutations.js
  7. +130 −0 addons/mail/static/src/js/wip/widget/autoresize_input.js
  8. +131 −0 addons/mail/static/src/js/wip/widget/chat_window.js
  9. +83 −0 addons/mail/static/src/js/wip/widget/chat_window_header.js
  10. +168 −0 addons/mail/static/src/js/wip/widget/chat_window_hidden_menu.js
  11. +185 −635 addons/mail/static/src/js/wip/widget/chat_window_manager.js
  12. +47 −8 addons/mail/static/src/js/wip/widget/composer.js
  13. +17 −0 addons/mail/static/src/js/wip/widget/discuss_root.js
  14. +3 −2 addons/mail/static/src/js/wip/widget/discuss_sidebar_item.js
  15. +17 −2 addons/mail/static/src/js/wip/widget/emojis_button.js
  16. +2 −2 addons/mail/static/src/js/wip/widget/thread.js
  17. +60 −0 addons/mail/static/src/js/wip/widget/thread_icon.js
  18. 0 addons/mail/static/src/scss/wip/{ → old_widget}/discuss.scss
  19. +36 −0 addons/mail/static/src/scss/wip/widget/chat_window.scss
  20. +70 −0 addons/mail/static/src/scss/wip/widget/chat_window_header.scss
  21. +83 −0 addons/mail/static/src/scss/wip/widget/chat_window_hidden_menu.scss
  22. +19 −0 addons/mail/static/src/scss/wip/widget/chat_window_manager.scss
  23. +19 −9 addons/mail/static/src/scss/wip/{ → widget}/composer.scss
  24. 0 addons/mail/static/src/scss/wip/{ → widget}/discuss_mobile_mailbox_selection.scss
  25. 0 addons/mail/static/src/scss/wip/{ → widget}/discuss_mobile_navbar.scss
  26. 0 addons/mail/static/src/scss/wip/{ → widget}/discuss_root.scss
  27. 0 addons/mail/static/src/scss/wip/{ → widget}/discuss_sidebar.scss
  28. +0 −61 addons/mail/static/src/scss/wip/{ → widget}/discuss_sidebar_item.scss
  29. 0 addons/mail/static/src/scss/wip/{ → widget}/emojis_popover.scss
  30. +1 −0 addons/mail/static/src/scss/wip/{ → widget}/message.scss
  31. +3 −2 addons/mail/static/src/scss/wip/{ → widget}/message_list.scss
  32. 0 addons/mail/static/src/scss/wip/{ → widget}/thread.scss
  33. +69 −0 addons/mail/static/src/scss/wip/widget/thread_icon.scss
  34. +10 −0 addons/mail/static/src/xml/wip/widget/autoresize_input.xml
  35. +16 −0 addons/mail/static/src/xml/wip/widget/chat_window.xml
  36. +26 −0 addons/mail/static/src/xml/wip/widget/chat_window_header.xml
  37. +34 −0 addons/mail/static/src/xml/wip/widget/chat_window_hidden_menu.xml
  38. +19 −0 addons/mail/static/src/xml/wip/widget/chat_window_manager.xml
  39. +33 −23 addons/mail/static/src/xml/wip/widget/composer.xml
  40. +3 −2 addons/mail/static/src/xml/wip/widget/discuss_root.xml
  41. +2 −25 addons/mail/static/src/xml/wip/widget/discuss_sidebar_item.xml
  42. +4 −2 addons/mail/static/src/xml/wip/widget/message.xml
  43. +1 −1 addons/mail/static/src/xml/wip/widget/message_list.xml
  44. +40 −0 addons/mail/static/src/xml/wip/widget/thread_icon.xml
  45. +21 −11 addons/mail/views/mail_templates.xml
  46. +212 −168 addons/web/static/lib/owl/owl.js
  47. +1 −1 addons/web/static/src/js/chrome/abstract_web_client.js
  48. +1 −1 addons/web/static/src/js/core/session.js
@@ -64,6 +64,11 @@
'static/src/xml/wip/old_widget/discuss.xml',
'static/src/xml/wip/old_widget/discuss_invite_partner_dialog.xml',
'static/src/xml/wip/widget/autocomplete_input.xml',
'static/src/xml/wip/widget/autoresize_input.xml',
'static/src/xml/wip/widget/chat_window.xml',
'static/src/xml/wip/widget/chat_window_header.xml',
'static/src/xml/wip/widget/chat_window_hidden_menu.xml',
'static/src/xml/wip/widget/chat_window_manager.xml',
'static/src/xml/wip/widget/composer.xml',
'static/src/xml/wip/widget/discuss_mobile_mailbox_selection.xml',
'static/src/xml/wip/widget/discuss_mobile_navbar.xml',
@@ -76,6 +81,7 @@
'static/src/xml/wip/widget/message.xml',
'static/src/xml/wip/widget/message_list.xml',
'static/src/xml/wip/widget/thread.xml',
'static/src/xml/wip/widget/thread_icon.xml',
'static/src/xml/wip/widget/thread_preview_list.xml',
],
}
@@ -6,7 +6,6 @@ const StoreMixin = require('mail.wip.old_widget.StoreMixin');
const Root = require('mail.wip.widget.DiscussRoot');

const AbstractAction = require('web.AbstractAction');
const config = require('web.config');
const core = require('web.core');
const session = require('web.session');

@@ -1,41 +1,69 @@
odoo.define('mail.wip.service.ChatWindowService', function (require) {
"use strict";

var StoreMixin = require('mail.wip.old_widget.StoreMixin');
var Root = require('mail.wip.widget.ChatWindowManager');
const StoreMixin = require('mail.wip.old_widget.StoreMixin');
const Root = require('mail.wip.widget.ChatWindowManager');

var AbstractService = require('web.AbstractService');
var core = require('web.core');
const AbstractService = require('web.AbstractService');
const core = require('web.core');
const session = require('web.session');

var _t = core._t;
const _t = core._t;

var ChatWindowService = AbstractService.extend(StoreMixin, {
const ChatWindowService = AbstractService.extend(StoreMixin, {
DEBUG: true,
dependencies: ['store'],
init() {
this._super.apply(this, arguments);
this._webClientReady = false;
if (this.DEBUG) {
window.chat_window_manager = this;
}
},
/**
* @override {web.AbstractService}
*/
init: function () {
start() {
this._super.apply(this, arguments);
core.bus.on('web_client_ready', this, async () => {
await this._mount();
this._webClientReady = true;
});
core.bus.on('show_home_menu', this, async () => {
if (!this._webClientReady) {
return;
}
if (document.querySelector('.o_wip_chat_window_manager')) {
return;
}
await this._mount();
});
},

//--------------------------------------------------------------------------
// Private
//--------------------------------------------------------------------------

/**
* @override {web.AbstractService}
* @private
*/
async start() {
this._super.apply(this, arguments);
async _mount() {
await this.awaitStore();
const env = {
_t,
qweb: core.qwebOwl,
session,
store: this.store,
call: (...args) => this.call(...args),
do_action: (...args) => this.do_action(...args),
rpc: (...args) => this._rpc(...args),
_t,
};
this._root = new Root(env);
this._root.mount(this.$el[0]); // aku todo
this.root = new Root(env);
this.root.mount(document.querySelector('body'));
},
});

// core.serviceRegistry.add('chat_window', ChatWindowService);
core.serviceRegistry.add('chat_window', ChatWindowService);

return ChatWindowService;

@@ -22,6 +22,9 @@ function initializeState() {
$pinnedThreads: [],
FETCH_LIMIT: 30, // max number of fetched messages from the server
cannedResponses: {},
chat_window_manager: {
$detachedThreads: [],
},
commands: {},
discuss: {
$thread: undefined,
@@ -30,6 +33,10 @@ function initializeState() {
menu_id: undefined,
stringifiedDomain: '[]',
},
global: {
innerHeight: window.innerHeight,
innerWidth: window.innerWidth,
},
isMobile: config.device.isMobile,
isMyselfModerator: false,
mailFailures: {},
@@ -39,7 +46,7 @@ function initializeState() {
partners: { odoobot }, // all partner infos
pinnedDmPartnerIDs: [], // partner_ids we have a pinned DM chat with
threadCaches: {},
threads: {} // all threads, including channels, DM, mailboxes, document threads, ...
threads: {}, // all threads, including channels, DM, mailboxes, document threads, ...
};
}

@@ -72,10 +79,15 @@ const StoreService = AbstractService.extend({
*/
start() {
this.ready = new Promise(resolve =>
this.store.dispatch('init', { ready: resolve })
this.store.dispatch('init', {
ready: () => {
this.store.commit('global/resize');
resolve();
}
})
);
window.addEventListener('resize', _.throttle(() => {
this.store.commit('update', { isMobile: config.device.isMobile });
window.addEventListener('resize', _.debounce(() => {
this.store.commit('global/resize');
}), 100);
},

@@ -93,8 +93,12 @@ const actions = {
}
});
const $thread = commit('thread/create', { ...data });
if (autoselect && state.discuss.open) {
commit('discuss/update', { $thread });
if (autoselect) {
if (state.discuss.open) {
commit('discuss/update', { $thread });
} else {
commit('chat_window_manager/open', { $thread });
}
}
},
/**
@@ -120,11 +124,15 @@ const actions = {
args: [[channelID]]
});
const $thread = commit('thread/create', { ...data });
if (autoselect && state.discuss.open) {
commit('discuss/update', {
$thread,
domain: [],
});
if (autoselect) {
if (state.discuss.open) {
commit('discuss/update', {
$thread,
domain: [],
});
} else {
commit('chat_window_manager/open', { $thread });
}
}
},
/**
@@ -7,12 +7,25 @@ const Partner = require('mail.wip.model.Partner');
const Thread = require('mail.wip.model.Thread');
const ThreadCache = require('mail.wip.model.ThreadCache');

const config = require('web.config');
const core = require('web.core');
const session = require('web.session');

const _t = core._t;

const mutations = {
/**
* @param {Object} param0
* @param {Object} param0.state
* @param {Object} param1
* @param {string} param1.$thread
*/
'chat_window_manager/open'({ state }, { $thread }) {
if (state.chat_window_manager.$detachedThreads.includes($thread)) {
return;
}
state.chat_window_manager.$detachedThreads.push($thread);
},
/**
* @param {Object} param0
* @param {Object} param0.state
@@ -925,6 +938,15 @@ const mutations = {
'update'({ state }, changes) {
Object.assign(state, changes);
},
/**
* @param {Object} param0
* @param {Object} param0.state
*/
'global/resize'({ state }) {
state.global.innerHeight = window.innerHeight;
state.global.innerWidth = window.innerWidth;
state.isMobile = config.device.isMobile;
},
};

return mutations;
@@ -0,0 +1,130 @@
odoo.define('mail.wip.widget.AutoresizeInput', function () {
'use strict';

const { Component } = owl;

class AutoresizeInput extends Component {

/**
* @param {...any} args
*/
constructor(...args) {
super(...args);
this.template = 'mail.wip.widget.AutoresizeInput';
this._scrollable = false;
}

mounted() {
this.el.setAttribute('rows', this.options.rows);
this._compute();
}

//--------------------------------------------------------------------------
// Getter / Setter
//--------------------------------------------------------------------------

/**
* @return {Object}
*/
get options() {
let options = this.props.options || {};
if (!('rows' in options)) {
options.rows = 1;
}
if (!('maxHeight' in options)) {
options.maxHeight = 200;
}
return options;
}

/**
* @return {string}
*/
get value() {
return this.el.value;
}

/**
* @param {string} newValue
*/
set value(newValue) {
this.el.value = newValue;
}

//--------------------------------------------------------------------------
// Public
//--------------------------------------------------------------------------

focus() {
this.el.focus();
}

/**
* @return {Object}
*/
getSelectionRange() {
return {
start: this.el.selectionStart,
end: this.el.selectionEnd,
};
}

/**
* @param {integer} start
* @param {integer} end
*/
setSelectionRange(start, end) {
this.el.setSelectionRange(start, end);
}

//--------------------------------------------------------------------------
// Private
//--------------------------------------------------------------------------

/**
* @private
*/
_compute() {
let prevScrollTop;
if (this._scrollable) {
prevScrollTop = this.el.scrollTop;
}
this.el.style['overflow-y'] = 'hidden';
this.el.style['height'] = 'auto';
this.el.style['height'] = `${this.el.scrollHeight}px`;
this.el.style['resize'] = 'none';
if (this.el.scrollHeight > this.options.maxHeight) {
this.el.style['height'] = `${this.options.maxHeight}px`;
this.el.style['overflow-y'] = 'auto';
if (prevScrollTop && this.el.scrollTop !== prevScrollTop) {
this.el.scrollTop = prevScrollTop;
}
this._scrollable = true;
} else {
this.el.style['overflow-y'] = 'hidden';
this._scrollable = false;
}
}

//--------------------------------------------------------------------------
// Handlers
//--------------------------------------------------------------------------

/**
* @private
*/
_onInput() {
this. _compute();
}
/**
* @private
* @param {KeyboardEvent} ev
*/
_onKeydown(ev) {
this.trigger('keydown', ev);
}
}

return AutoresizeInput;

});
Oops, something went wrong.

0 comments on commit f2f15cc

Please sign in to comment.
You can’t perform that action at this time.