[FIX] mail: allow focus on any rtc session
Before this commit, in the rtc call viewer, it was only possible to focus videos, this commit changes that by allowing to focus any rtc session. This is a first step in improving the focusing and layout system. This commit also changes the call viewer and call participant card templates to ensure that they remain consistent when focusing non-video sessions, which also fixes a bug which caused avatars to not be round when the displayed image had an aspect ratio other than 1. closes odoo/odoo#79862 X-original-commit: d49407423164c44e86558cd2fc4f6c3ae47aed25 Signed-off-by: Sébastien Theys (seb) <seb@odoo.com>
This commit is contained in:
+23
-14
@@ -8,16 +8,21 @@
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.o_RtcCallParticipantCard_avatar {
|
||||
.o_RtcCallParticipantCard_avatarFrame {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
max-height: 100%;
|
||||
user-select: none;
|
||||
aspect-ratio: 16/9;
|
||||
|
||||
&.o-isMinimized {
|
||||
aspect-ratio: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.o_RtcCallParticipantCard_avatarImage {
|
||||
max-height: 100px;
|
||||
max-width: 100px;
|
||||
max-height: #{"min(100%, 100px)"}; // interpolated as not supported by Sass
|
||||
max-width: #{"min(100%, 100px)"};
|
||||
aspect-ratio: 1;
|
||||
object-fit: cover;
|
||||
border: 5px solid gray('700');
|
||||
|
||||
&.o-isTalking {
|
||||
@@ -74,6 +79,7 @@
|
||||
max-width: 50%;
|
||||
overflow: hidden;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.o_RtcCallParticipantCard_overlayTop {
|
||||
@@ -110,8 +116,12 @@
|
||||
.o_RtcCallParticipantCard {
|
||||
border-radius: $o-mail-rounded-rectangle-border-radius-sm;
|
||||
|
||||
&.o-isClickable {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
&.o-isTalking {
|
||||
box-shadow: inset 0 0 0 map-get($spacers, 2) darken($o-enterprise-primary-color, 5%);
|
||||
box-shadow: inset 0 0 0 map-get($spacers, 1) darken($o-enterprise-primary-color, 5%);
|
||||
}
|
||||
|
||||
&.o-isInvitation {
|
||||
@@ -119,20 +129,19 @@
|
||||
}
|
||||
}
|
||||
|
||||
.o_RtcCallParticipantCard_avatarFrame {
|
||||
border-radius: $o-mail-rounded-rectangle-border-radius-sm;
|
||||
&:not(.o-isMinimized) {
|
||||
background-color: $o-brand-secondary;
|
||||
}
|
||||
}
|
||||
|
||||
.o_RtcCallParticipantCard_connectionState {
|
||||
color: theme-color('warning');
|
||||
}
|
||||
|
||||
.o_RtcCallParticipantCard_container {
|
||||
border-radius: $o-mail-rounded-rectangle-border-radius-sm;
|
||||
|
||||
&.o-canClick {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
&:not(.o-isMinimized) {
|
||||
background-color: $o-brand-secondary;
|
||||
}
|
||||
}
|
||||
|
||||
.o_RtcCallParticipantCard_liveIndicator {
|
||||
|
||||
+11
-16
@@ -4,33 +4,30 @@
|
||||
<t t-name="mail.RtcCallParticipantCard" owl="1">
|
||||
<div class="o_RtcCallParticipantCard"
|
||||
t-att-class="{
|
||||
'o-isClickable': callParticipantCard.invitedGuest or callParticipantCard.invitedPartner or !callParticipantCard.isMinimized,
|
||||
'o-isTalking': callParticipantCard and !callParticipantCard.isMinimized and callParticipantCard.isTalking,
|
||||
'o-isInvitation': callParticipantCard and callParticipantCard.isInvitation,
|
||||
}"
|
||||
t-on-contextmenu="_onContextMenu"
|
||||
>
|
||||
<t t-if="callParticipantCard">
|
||||
<div class="o_RtcCallParticipantCard_container"
|
||||
t-att-class="{
|
||||
'o-isMinimized': callParticipantCard.isMinimized,
|
||||
'o-canClick': !callParticipantCard.isInvitation,
|
||||
}"
|
||||
<div class="o_RtcCallParticipantCard_container align-items-center"
|
||||
t-att-title="callParticipantCard.name"
|
||||
t-att-aria-label="callParticipantCard.name"
|
||||
t-on-click="callParticipantCard.onClick"
|
||||
>
|
||||
<!-- card -->
|
||||
<t t-if="callParticipantCard.rtcSession and callParticipantCard.rtcSession.videoStream">
|
||||
<RtcVideo t-on-click="callParticipantCard.onClickVideo" rtcSessionLocalId="callParticipantCard.rtcSession.localId"/>
|
||||
<RtcVideo rtcSessionLocalId="callParticipantCard.rtcSession.localId"/>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<div class="o_RtcCallParticipantCard_avatar" draggable="false">
|
||||
<div class="o_RtcCallParticipantCard_avatarFrame mh-100 mw-100 h-100 align-items-center justify-content-center" t-att-class="{ 'o-isMinimized': callParticipantCard.isMinimized }" draggable="false">
|
||||
<img alt="Avatar"
|
||||
t-att-class="{
|
||||
'o-isTalking': callParticipantCard.isTalking,
|
||||
'o-isInvitation': callParticipantCard.isInvitation,
|
||||
}"
|
||||
class="o_RtcCallParticipantCard_avatarImage rounded-circle"
|
||||
class="o_RtcCallParticipantCard_avatarImage h-100 rounded-circle"
|
||||
t-att-src="callParticipantCard.avatarUrl"
|
||||
draggable="false"
|
||||
/>
|
||||
@@ -79,14 +76,12 @@
|
||||
|
||||
<!-- volume popover -->
|
||||
<t t-if="!callParticipantCard.rtcSession.isOwnSession">
|
||||
<i class="o_RtcCallParticipantCard_volumeMenuAnchor">
|
||||
<Popover>
|
||||
<i t-ref="volumeMenuAnchor"/>
|
||||
<t t-set="opened">
|
||||
<input type="range" min="0.0" max="1" step="0.01" t-att-value="callParticipantCard.rtcSession.volume" t-on-change="callParticipantCard.onChangeVolume"/>
|
||||
</t>
|
||||
</Popover>
|
||||
</i>
|
||||
<Popover>
|
||||
<i class="o_RtcCallParticipantCard_volumeMenuAnchor" t-on-click="callParticipantCard.onClickVolumeAnchor" t-ref="volumeMenuAnchor"/>
|
||||
<t t-set="opened">
|
||||
<input type="range" min="0.0" max="1" step="0.01" t-att-value="callParticipantCard.rtcSession.volume" t-on-change="callParticipantCard.onChangeVolume"/>
|
||||
</t>
|
||||
</Popover>
|
||||
</t>
|
||||
</t>
|
||||
|
||||
|
||||
@@ -77,12 +77,7 @@
|
||||
aspect-ratio: 16/9;
|
||||
}
|
||||
|
||||
.o_RtcCallViewer_mainParticipant {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.o_RtcCallViewer_mainParticipantContainer {
|
||||
max-height: 100%;
|
||||
display: flex;
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
@@ -11,9 +11,9 @@
|
||||
<!-- Call members display -->
|
||||
<div class="o_RtcCallViewer_participantContainer" t-on-click="rtcCallViewer.onClick" t-on-mousemove="rtcCallViewer.onMouseMove">
|
||||
<t t-if="rtcCallViewer.layout !== 'tiled'">
|
||||
<div class="o_RtcCallViewer_mainParticipantContainer">
|
||||
<div class="o_RtcCallViewer_mainParticipantContainer justify-content-center mw-100 mh-100">
|
||||
<t t-if="rtcCallViewer.mainParticipantCard">
|
||||
<RtcCallParticipantCard class="o_RtcCallViewer_participantCard o_RtcCallViewer_mainParticipant" callParticipantCardLocalId="rtcCallViewer.mainParticipantCard.localId"/>
|
||||
<RtcCallParticipantCard class="o_RtcCallViewer_participantCard w-100" callParticipantCardLocalId="rtcCallViewer.mainParticipantCard.localId"/>
|
||||
</t>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
@@ -163,7 +163,7 @@ function factory(dependencies) {
|
||||
id: sessionId,
|
||||
});
|
||||
const focusedSessionId = this.focusedRtcSession && this.focusedRtcSession.id;
|
||||
if (!sessionId || focusedSessionId === sessionId || !rtcSession.videoStream) {
|
||||
if (!sessionId || focusedSessionId === sessionId) {
|
||||
this.update({ focusedRtcSession: unlink() });
|
||||
return;
|
||||
}
|
||||
@@ -304,9 +304,7 @@ function factory(dependencies) {
|
||||
isCausal: true,
|
||||
readonly: true,
|
||||
}),
|
||||
focusedRtcSession: one2one('mail.rtc_session', {
|
||||
inverse: 'focusingMessaging',
|
||||
}),
|
||||
focusedRtcSession: one2one('mail.rtc_session'),
|
||||
/**
|
||||
* Mailbox History.
|
||||
*/
|
||||
|
||||
+12
-4
@@ -2,6 +2,7 @@
|
||||
|
||||
import { registerNewModel } from '@mail/model/model_core';
|
||||
import { attr, many2one, one2one } from '@mail/model/model_field';
|
||||
import { isEventHandled, markEventHandled } from '@mail/utils/utils';
|
||||
|
||||
function factory(dependencies) {
|
||||
|
||||
@@ -14,7 +15,7 @@ function factory(dependencies) {
|
||||
super._created();
|
||||
this.onChangeVolume = this.onChangeVolume.bind(this);
|
||||
this.onClick = this.onClick.bind(this);
|
||||
this.onClickVideo = this.onClickVideo.bind(this);
|
||||
this.onClickVolumeAnchor = this.onClickVolumeAnchor.bind(this);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
@@ -32,7 +33,13 @@ function factory(dependencies) {
|
||||
* @param {MouseEvent} ev
|
||||
*/
|
||||
async onClick(ev) {
|
||||
if (isEventHandled(ev, 'CallParticipantCard.clickVolumeAnchor')) {
|
||||
return;
|
||||
}
|
||||
if (!this.invitedPartner && !this.invitedGuest) {
|
||||
if (!this.isMinimized) {
|
||||
this.messaging.toggleFocusedRtcSession(this.rtcSession.id);
|
||||
}
|
||||
return;
|
||||
}
|
||||
const channel = this.channel;
|
||||
@@ -51,11 +58,12 @@ function factory(dependencies) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Handled by the popover component.
|
||||
*
|
||||
* @param {MouseEvent} ev
|
||||
*/
|
||||
async onClickVideo(ev) {
|
||||
ev.stopPropagation();
|
||||
this.messaging.toggleFocusedRtcSession(this.rtcSession.id);
|
||||
async onClickVolumeAnchor(ev) {
|
||||
markEventHandled(ev, 'CallParticipantCard.clickVolumeAnchor');
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
@@ -181,10 +181,13 @@ function factory(dependencies) {
|
||||
if (!this.threadView) {
|
||||
return 'tiled';
|
||||
}
|
||||
if (this.isMinimized) {
|
||||
return 'tiled';
|
||||
}
|
||||
if (!this.threadView.thread.rtc) {
|
||||
return 'tiled';
|
||||
}
|
||||
if (!this.threadView.thread.videoCount || !this.mainParticipantCard) {
|
||||
if (!this.mainParticipantCard) {
|
||||
return 'tiled';
|
||||
}
|
||||
if (
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
import { registerNewModel } from '@mail/model/model_core';
|
||||
import { attr, one2one } from '@mail/model/model_field';
|
||||
import { clear } from '@mail/model/model_field_command';
|
||||
|
||||
function factory(dependencies) {
|
||||
|
||||
@@ -35,6 +36,9 @@ function factory(dependencies) {
|
||||
this.callViewer.update({
|
||||
filterVideoGrid: true,
|
||||
});
|
||||
if (this.messaging.focusedRtcSession && !this.messaging.focusedRtcSession.videoStream) {
|
||||
this.messaging.update({ focusedRtcSession: clear() });
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,8 +4,7 @@ import { browser } from "@web/core/browser/browser";
|
||||
|
||||
import { registerNewModel } from '@mail/model/model_core';
|
||||
import { attr, many2one, one2one, one2many } from '@mail/model/model_field';
|
||||
import { clear, unlink } from '@mail/model/model_field_command';
|
||||
import { OnChange } from '@mail/model/model_onchange';
|
||||
import { clear } from '@mail/model/model_field_command';
|
||||
|
||||
function factory(dependencies) {
|
||||
|
||||
@@ -283,15 +282,6 @@ function factory(dependencies) {
|
||||
}, delay);
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_onChangeVideoStream() {
|
||||
if (!this.videoStream) {
|
||||
this.update({ focusingMessaging: unlink() });
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* cleanly removes the audio stream of the session
|
||||
*
|
||||
@@ -349,13 +339,6 @@ function factory(dependencies) {
|
||||
connectionState: attr({
|
||||
default: 'Waiting for the peer to send a RTC offer',
|
||||
}),
|
||||
/**
|
||||
* If this field is set, this session is 'focused' which means that it will
|
||||
* be displayed as the main session.
|
||||
*/
|
||||
focusingMessaging: one2one('mail.messaging', {
|
||||
inverse: 'focusedRtcSession',
|
||||
}),
|
||||
guest: many2one('mail.guest', {
|
||||
inverse: 'rtcSessions',
|
||||
}),
|
||||
@@ -470,12 +453,6 @@ function factory(dependencies) {
|
||||
compute: '_computeVolume',
|
||||
}),
|
||||
};
|
||||
RtcSession.onChanges = [
|
||||
new OnChange({
|
||||
dependencies: ['videoStream'],
|
||||
methodName: '_onChangeVideoStream',
|
||||
}),
|
||||
];
|
||||
RtcSession.identifyingFields = ['id'];
|
||||
RtcSession.modelName = 'mail.rtc_session';
|
||||
|
||||
|
||||
Reference in New Issue
Block a user