[REF] mail: separate the tile model based on the parent view

Before this commit, the `callParticipantCard` model was used separately
for both the main session and the multi-tile views
(`CallSidebarView`/`CallMainView`), this commit makes so that each
multi-tile view has its own list of tiles.

part of task-2692836

closes odoo/odoo#96868

Signed-off-by: Sébastien Theys (seb) <seb@odoo.com>
This commit is contained in:
Thanh Dodeur
2022-07-28 05:04:29 +02:00
parent 33ed562cab
commit 2cbad9a3f7
9 changed files with 162 additions and 124 deletions
@@ -6,10 +6,6 @@
min-width: 0;
}
.o_CallMainView_mainParticipantContainer {
min-width: 0;
}
.o_CallMainView_gridParticipantCard {
width: var(--width);
height: var(--height);
@@ -30,10 +26,6 @@
// Style
// ------------------------------------------------------------------
.o_CallMainView_mainParticipantContainer {
background-color: black;
}
.o_CallMainView_sidebarButton {
color: white;
border-radius: 10px 0px 0px 10px;
@@ -3,36 +3,28 @@
<t t-name="mail.CallMainView" owl="1">
<t t-if="callMainView">
<div class="o_CallMainView d-flex flex-grow-1 flex-column align-items-center justify-content-center" t-ref="root" t-on-mouseleave="callMainView.onMouseleave">
<div class="o_CallMainView d-flex flex-grow-1 flex-column align-items-center justify-content-center position-relative bg-black-50" t-ref="root" t-on-mouseleave="callMainView.onMouseleave">
<t t-set="dummy" t-value="messaging and messaging.device and messaging.device.globalWindowInnerHeight and messaging.device.globalWindowInnerWidth"/>
<div class="o_CallMainView_participantContainer d-flex justify-content-between w-100 h-100 overflow-hidden" t-on-click="callMainView.onClick" t-on-mousemove="callMainView.onMouseMove">
<t t-if="callMainView.callView.mainParticipantCard">
<div class="o_CallMainView_mainParticipantContainer d-flex flex-grow-1 justify-content-center position-relative mw-100 mh-100">
<CallParticipantCard className="'o_CallMainView_participantCard'" record="callMainView.callView.mainParticipantCard"/>
<t t-if="callMainView.showOverlay and !callMainView.callView.threadView.compact">
<i t-if="callMainView.callView.hasSidebar" class="o_CallMainView_sidebarButton o_cursor_pointer position-absolute fa fa-arrow-right" title="Hide sidebar" t-on-click="callMainView.onClickHideSidebar"/>
<i t-else="" class="o_CallMainView_sidebarButton o_cursor_pointer position-absolute fa fa-arrow-left" title="Show sidebar" t-on-click="callMainView.onClickShowSidebar"/>
</t>
</div>
</t>
<t t-elif="callMainView.callView.tileParticipantCards.length > 0">
<div
class="o_CallMainView_grid d-flex align-items-center overflow-hidden h-100 w-100 flex-wrap justify-content-center"
t-ref="tileContainer"
t-attf-style="--height:{{callMainView.tileHeight}}px; --width:{{callMainView.tileWidth}}px;"
>
<t t-foreach="callMainView.callView.tileParticipantCards" t-as="participantCard" t-key="'grid_tile_'+participantCard.localId">
<CallParticipantCard
className="'o_CallMainView_gridParticipantCard'"
record="participantCard"
/>
</t>
</div>
<div
class="o_CallMainView_grid d-flex align-items-center overflow-hidden h-100 w-100 flex-wrap justify-content-center"
t-attf-style="--height:{{callMainView.tileHeight}}px; --width:{{callMainView.tileWidth}}px;"
t-on-click="callMainView.onClick"
t-on-mousemove="callMainView.onMouseMove"
t-ref="tileContainer"
>
<t t-foreach="callMainView.mainTiles" t-as="tile" t-key="'grid_tile_'+tile.localId">
<CallParticipantCard
className="'o_CallMainView_gridParticipantCard'"
record="tile.participantCard"
/>
</t>
</div>
<!-- Buttons -->
<t t-if="callMainView.hasSidebarButton">
<i t-if="callMainView.callView.isSidebarOpen" class="o_CallMainView_sidebarButton o_cursor_pointer position-absolute fa fa-arrow-right" title="Hide sidebar" t-on-click="callMainView.onClickHideSidebar"/>
<i t-else="" class="o_CallMainView_sidebarButton o_cursor_pointer position-absolute fa fa-arrow-left" title="Show sidebar" t-on-click="callMainView.onClickShowSidebar"/>
</t>
<t t-if="callMainView.showOverlay or !callMainView.isControllerFloating">
<div class="o_CallMainView_controls d-flex justify-content-center w-100 pb-1" t-att-class="{ 'o-isFloating position-absolute bottom-0 pb-3': callMainView.isControllerFloating }">
<div class="o_CallMainView_controlsOverlayContainer" t-on-mousemove="callMainView.onMouseMoveOverlay">
@@ -4,10 +4,10 @@
<t t-name="mail.CallSidebarView" owl="1">
<t t-if="callSidebarView">
<div class="o_CallSidebarView d-flex align-items-center h-100 flex-column">
<t t-foreach="callSidebarView.callView.tileParticipantCards" t-as="participantCard" t-key="participantCard.localId">
<t t-foreach="callSidebarView.sidebarTiles" t-as="tile" t-key="tile.localId">
<CallParticipantCard
className="'o_CallSidebarView_participantCard w-100'"
record="participantCard"
record="tile.participantCard"
/>
</t>
</div>
@@ -1,8 +1,8 @@
/** @odoo-module **/
import { registerModel } from '@mail/model/model_core';
import { attr, one } from '@mail/model/model_field';
import { clear, insertAndReplace } from '@mail/model/model_field_command';
import { attr, many, one } from '@mail/model/model_field';
import { clear, insertAndReplace, replace } from '@mail/model/model_field_command';
import { isEventHandled, markEventHandled } from '@mail/utils/utils';
@@ -63,13 +63,13 @@ registerModel({
* @param {MouseEvent} ev
*/
onClickHideSidebar(ev) {
this.callView.update({ hasSidebar: false });
this.callView.update({ isSidebarOpen: false });
},
/**
* @param {MouseEvent} ev
*/
onClickShowSidebar(ev) {
this.callView.update({ hasSidebar: true });
this.callView.update({ isSidebarOpen: true });
},
/**
* @param {MouseEvent} ev
@@ -117,12 +117,29 @@ registerModel({
// Private
//----------------------------------------------------------------------
/**
* @private
* @returns {boolean}
*/
_computeHasSidebarButton() {
return Boolean(this.callView.activeRtcSession && this.showOverlay && !this.callView.threadView.compact);
},
/**
* @private
*/
_computeIsControllerFloating() {
return Boolean(this.callView.isFullScreen || this.callView.activeRtcSession && !this.callView.threadView.compact);
},
/**
* @private
* @returns {FieldCommand}
*/
_computeMainTiles() {
if (this.callView.activeRtcSession) {
return insertAndReplace([{ channelMember: replace(this.callView.activeRtcSession.channelMember) }]);
}
return insertAndReplace(this.callView.filteredChannelMembers.map(channelMember => ({ channelMember: replace(channelMember) })));
},
/**
* Shows the overlay (buttons) for a set a mount of time.
*
@@ -154,6 +171,9 @@ registerModel({
related: 'callView.channel',
required: true,
}),
hasSidebarButton: attr({
compute: '_computeHasSidebarButton',
}),
/**
* Determines if the controller is an overlay or a bottom bar.
*/
@@ -161,6 +181,11 @@ registerModel({
default: false,
compute: '_computeIsControllerFloating',
}),
mainTiles: many('CallMainViewTile', {
compute: '_computeMainTiles',
inverse: 'callMainViewOwner',
isCausal: true,
}),
/**
* Determines if we show the overlay with the control buttons.
*/
@@ -0,0 +1,26 @@
/** @odoo-module **/
import { registerModel } from '@mail/model/model_core';
import { insertAndReplace } from '@mail/model/model_field_command';
import { one } from '@mail/model/model_field';
registerModel({
name: 'CallMainViewTile',
identifyingFields: ['callMainViewOwner', 'channelMember'],
fields: {
callMainViewOwner: one('CallMainView', {
inverse: 'mainTiles',
readonly: true,
required: true,
}),
channelMember: one('ChannelMember', {
readonly: true,
required: true,
}),
participantCard: one('CallParticipantCard', {
default: insertAndReplace(),
inverse: 'mainViewTileOwner',
isCausal: true,
}),
},
});
@@ -9,7 +9,7 @@ import { sprintf } from '@web/core/utils/strings';
registerModel({
name: 'CallParticipantCard',
identifyingFields: ['channelMember', ['callViewAsMainCard', 'callViewAsTile']],
identifyingFields: [['sidebarViewTileOwner', 'mainViewTileOwner']],
recordMethods: {
/**
* @param {Event} ev
@@ -25,7 +25,7 @@ registerModel({
return;
}
if (this.rtcSession) {
if (this.callView.activeRtcSession === this.rtcSession && this.callViewAsMainCard) {
if (this.callView.activeRtcSession === this.rtcSession && this.mainViewTileOwner) {
this.callView.update({ activeRtcSession: clear() });
} else {
this.callView.update({ activeRtcSession: replace(this.rtcSession) });
@@ -68,16 +68,24 @@ registerModel({
},
/**
* @private
* @returns {mail.callView}
* @returns {FieldCommand}
*/
_computeCallView() {
const callView = this.callViewAsMainCard || this.callViewAsTile;
if (callView) {
return replace(callView);
} else {
return clear();
if (this.sidebarViewTileOwner) {
return replace(this.sidebarViewTileOwner.callSidebarViewOwner.callView);
}
return replace(this.mainViewTileOwner.callMainViewOwner.callView);
},
/**
* @private
* @returns {FieldCommand}
*/
_computeChannelMember() {
if (this.sidebarViewTileOwner) {
return replace(this.sidebarViewTileOwner.channelMember);
}
return replace(this.mainViewTileOwner.channelMember);
},
/**
* @private
* @returns {boolean}
@@ -144,9 +152,8 @@ registerModel({
},
fields: {
channelMember: one('ChannelMember', {
compute: '_computeChannelMember',
inverse: 'callParticipantCards',
required: true,
readonly: true,
}),
/**
* Determines whether or not we show the connection info.
@@ -160,6 +167,10 @@ registerModel({
inboundConnectionTypeText: attr({
compute: '_computeInboundConnectionTypeText',
}),
mainViewTileOwner: one('CallMainViewTile', {
inverse: 'participantCard',
readonly: true,
}),
/**
* Determines if this card has to be displayed in a minimized form.
*/
@@ -187,24 +198,14 @@ registerModel({
compute: '_computeCallView',
inverse: 'participantCards',
}),
/**
* The call view for which this card is the main card.
*/
callViewAsMainCard: one('CallView', {
inverse: 'mainParticipantCard',
readonly: true,
}),
/**
* The call view for which this card is one of the tiles.
*/
callViewAsTile: one('CallView', {
inverse: 'tileParticipantCards',
readonly: true,
}),
rtcSession: one('RtcSession', {
related: 'channelMember.rtcSession',
inverse: 'callParticipantCards',
}),
sidebarViewTileOwner: one('CallSidebarViewTile', {
inverse: 'participantCard',
readonly: true,
}),
callParticipantVideoView: one('CallParticipantVideoView', {
compute: '_computeCallParticipantVideoView',
inverse: 'callParticipantCardOwner',
@@ -1,16 +1,31 @@
/** @odoo-module **/
import { registerModel } from '@mail/model/model_core';
import { one } from '@mail/model/model_field';
import { many, one } from '@mail/model/model_field';
import { insertAndReplace, replace } from '@mail/model/model_field_command';
registerModel({
name: 'CallSidebarView',
identifyingFields: ['callView'],
recordMethods: {
/**
* @private
* @returns {FieldCommand}
*/
_computeSidebarTiles() {
return insertAndReplace(this.callView.filteredChannelMembers.map(channelMember => ({ channelMember: replace(channelMember) })));
},
},
fields: {
callView: one('CallView', {
inverse: 'callSidebarView',
required: true,
readonly: true,
})
required: true,
}),
sidebarTiles: many('CallSidebarViewTile', {
compute: '_computeSidebarTiles',
inverse: 'callSidebarViewOwner',
isCausal: true,
}),
},
});
@@ -0,0 +1,26 @@
/** @odoo-module **/
import { registerModel } from '@mail/model/model_core';
import { insertAndReplace } from '@mail/model/model_field_command';
import { one } from '@mail/model/model_field';
registerModel({
name: 'CallSidebarViewTile',
identifyingFields: ['callSidebarViewOwner', 'channelMember'],
fields: {
callSidebarViewOwner: one('CallSidebarView', {
inverse: 'sidebarTiles',
readonly: true,
required: true,
}),
channelMember: one('ChannelMember', {
readonly: true,
required: true,
}),
participantCard: one('CallParticipantCard', {
default: insertAndReplace(),
inverse: 'sidebarViewTileOwner',
isCausal: true,
}),
},
});
+19 -58
View File
@@ -5,7 +5,7 @@ import { browser } from "@web/core/browser/browser";
import { registerModel } from '@mail/model/model_core';
import { attr, many, one } from '@mail/model/model_field';
import { OnChange } from '@mail/model/model_onchange';
import { clear, insert, insertAndReplace, replace } from '@mail/model/model_field_command';
import { clear, insertAndReplace, replace } from '@mail/model/model_field_command';
registerModel({
name: 'CallView',
@@ -80,11 +80,21 @@ registerModel({
* @private
*/
_computeCallSideBarView() {
if (this.mainParticipantCard && this.hasSidebar && !this.threadView.compact) {
if (this.activeRtcSession && this.isSidebarOpen && !this.threadView.compact) {
return insertAndReplace();
}
return clear();
},
_computeFilteredChannelMembers() {
const channelMembers = [];
for (const channelMember of this.channel.channel.callParticipants) {
if (this.filterVideoGrid && !channelMember.isStreaming) {
continue;
}
channelMembers.push(channelMember);
}
return replace(channelMembers);
},
/**
* @private
*/
@@ -95,7 +105,7 @@ registerModel({
if (this.isFullScreen || this.threadView.compact) {
return false;
}
if (this.mainParticipantCard) {
if (this.activeRtcSession) {
return false;
}
return !this.channel.rtc || this.channel.videoCount === 0;
@@ -107,17 +117,6 @@ registerModel({
_computeLayoutSettingsTitle() {
return this.env._t("Change Layout");
},
/**
* @private
*/
_computeMainParticipantCard() {
if (!this.messaging || !this.activeRtcSession || !this.threadView || !this.activeRtcSession) {
return clear();
}
return insert({
channelMember: replace(this.activeRtcSession.channelMember),
});
},
/**
* @private
* @returns {string}
@@ -125,28 +124,6 @@ registerModel({
_computeSettingsTitle() {
return this.env._t("Settings");
},
/**
* @private
* @returns {FieldCommand}
*/
_computeTileParticipantCards() {
if (!this.threadView) {
return clear();
}
if (this.activeRtcSession && !this.hasSidebar) {
return clear();
}
const tileCards = [];
for (const channelMember of this.channel.channel.callParticipants) {
if (this.filterVideoGrid && !channelMember.isStreaming) {
continue;
}
tileCards.push({
channelMember: replace(channelMember),
});
}
return insertAndReplace(tileCards);
},
/**
* @private
*/
@@ -202,18 +179,15 @@ registerModel({
related: 'threadView.thread',
required: true,
}),
filteredChannelMembers: many('ChannelMember', {
compute: '_computeFilteredChannelMembers',
}),
/**
* Determines whether we only display the videos or all the participants
*/
filterVideoGrid: attr({
default: false,
}),
/**
* Determines if the viewer should have a sidebar.
*/
hasSidebar: attr({
default: true,
}),
/**
* Determines if the viewer should be displayed fullScreen.
*/
@@ -228,20 +202,15 @@ registerModel({
default: false,
compute: '_computeIsMinimized',
}),
isSidebarOpen: attr({
default: true,
}),
/**
* Text content that is displayed on title of the layout settings dialog.
*/
layoutSettingsTitle: attr({
compute: '_computeLayoutSettingsTitle',
}),
/**
* If set, the card to be displayed as the main card.
*/
mainParticipantCard: one('CallParticipantCard', {
compute: '_computeMainParticipantCard',
inverse: 'callViewAsMainCard',
isCausal: true,
}),
/**
* All the participant cards of the call viewer (main card and tile cards).
* this is a technical inverse to distinguish from the other relation 'tileParticipantCards'.
@@ -264,14 +233,6 @@ registerModel({
readonly: true,
required: true,
}),
/**
* List of all participant cards (can either be invitations or rtcSessions).
*/
tileParticipantCards: many('CallParticipantCard', {
compute: '_computeTileParticipantCards',
inverse: 'callViewAsTile',
isCausal: true,
}),
},
onChanges: [
new OnChange({