[IMP] mail: add rtc information to the member list
This commit adds call icons to the channel member list and sorts this list as well as the call participant cards of the call view based on call state (in call, raising hand, invited). task-3251025 closes odoo/odoo#117995 Signed-off-by: Alexandre Kühn (aku) <aku@odoo.com>
This commit is contained in:
@@ -378,7 +378,25 @@ export class Thread {
|
||||
orderedOnlineMembers.push(member);
|
||||
}
|
||||
}
|
||||
return orderedOnlineMembers.sort((m1, m2) => (m1.persona.name < m2.persona.name ? -1 : 1));
|
||||
return orderedOnlineMembers.sort((m1, m2) => {
|
||||
const m1HasRtc = Boolean(m1.rtcSession);
|
||||
const m2HasRtc = Boolean(m2.rtcSession);
|
||||
if (m1HasRtc === m2HasRtc) {
|
||||
/**
|
||||
* If raisingHand is falsy, it gets an Infinity value so that when
|
||||
* we sort by [oldest/lowest-value]-first, falsy values end up last.
|
||||
*/
|
||||
const m1RaisingValue = m1.rtcSession?.raisingHand || Infinity;
|
||||
const m2RaisingValue = m2.rtcSession?.raisingHand || Infinity;
|
||||
if (m1HasRtc && m1RaisingValue !== m2RaisingValue) {
|
||||
return m1RaisingValue - m2RaisingValue;
|
||||
} else {
|
||||
return m1.persona.name?.localeCompare(m2.persona.name) ?? 1;
|
||||
}
|
||||
} else {
|
||||
return m2HasRtc - m1HasRtc;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
get unknownMembersCount() {
|
||||
|
||||
@@ -33,7 +33,13 @@
|
||||
<ImStatus className="'position-absolute bottom-0 end-0'" persona="member.persona"/>
|
||||
</div>
|
||||
<span class="ms-2 text-truncate" t-esc="member.persona.name"/>
|
||||
<span t-if="member.rtcSession?.isRaisingHand" class="p-2 fa ms-auto fa-hand-paper-o"/>
|
||||
<span class="ms-auto">
|
||||
<span t-if="props.thread.invitedMemberIds.has(member.id)" class="p-1 fa fa-user-plus"/>
|
||||
<span t-if="member.rtcSession?.isSelfMuted and !member.rtcSession?.isDeaf" class="p-1 fa fa-microphone-slash"/>
|
||||
<span t-elif="member.rtcSession?.isDeaf" class="p-1 fa fa-deaf"/>
|
||||
<span t-if="member.rtcSession?.raisingHand" class="p-1 fa fa-hand-paper-o"/>
|
||||
</span>
|
||||
|
||||
</div>
|
||||
</t>
|
||||
|
||||
|
||||
@@ -72,25 +72,45 @@ export class Call extends Component {
|
||||
}
|
||||
|
||||
get visibleCards() {
|
||||
const cards = [];
|
||||
const raisingHandCards = [];
|
||||
const sessionCards = [];
|
||||
const invitationCards = [];
|
||||
const filterVideos = this.userSettings.showOnlyVideo && this.props.thread.videoCount > 0;
|
||||
for (const session of Object.values(this.props.thread.rtcSessions)) {
|
||||
if (!filterVideos || session.videoStream) {
|
||||
cards.push({
|
||||
const data = {
|
||||
key: "session_" + session.id,
|
||||
session,
|
||||
});
|
||||
};
|
||||
if (session.raisingHand) {
|
||||
raisingHandCards.push(data);
|
||||
} else {
|
||||
sessionCards.push(data);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!filterVideos) {
|
||||
for (const memberId of this.props.thread.invitedMemberIds) {
|
||||
cards.push({
|
||||
invitationCards.push({
|
||||
key: "member_" + memberId,
|
||||
member: this.store.channelMembers[memberId],
|
||||
});
|
||||
}
|
||||
}
|
||||
return cards;
|
||||
raisingHandCards.sort((c1, c2) => {
|
||||
return c1.session.raisingHand - c2.session.raisingHand;
|
||||
});
|
||||
sessionCards.sort((c1, c2) => {
|
||||
return (
|
||||
c1.session.channelMember?.persona?.name?.localeCompare(
|
||||
c2.session.channelMember?.persona?.name
|
||||
) ?? 1
|
||||
);
|
||||
});
|
||||
invitationCards.sort((c1, c2) => {
|
||||
return c1.member.persona?.name?.localeCompare(c2.member.persona?.name) ?? 1;
|
||||
});
|
||||
return raisingHandCards.concat(sessionCards, invitationCards);
|
||||
}
|
||||
|
||||
get visibleMainCards() {
|
||||
|
||||
@@ -36,7 +36,7 @@ export class CallActionList extends Component {
|
||||
}
|
||||
|
||||
async onClickRaiseHand(ev) {
|
||||
this.rtc.raiseHand(!this.rtc.state.selfSession.isRaisingHand);
|
||||
this.rtc.raiseHand(!this.rtc.state.selfSession.raisingHand);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -37,10 +37,10 @@
|
||||
}"/>
|
||||
</div>
|
||||
</button>
|
||||
<t t-if="rtc.state?.selfSession.isRaisingHand" t-set="handText">Lower hand</t>
|
||||
<t t-if="rtc.state?.selfSession.raisingHand" t-set="handText">Lower hand</t>
|
||||
<t t-else="" t-set="handText">Raise hand</t>
|
||||
<button class="btn d-flex m-1 border-0 rounded-circle shadow-none opacity-100 opacity-75-hover"
|
||||
t-att-class="{ 'p-2': isSmall, 'p-3': !isSmall, 'bg-500' : rtc.state?.selfSession.isRaisingHand }"
|
||||
t-att-class="{ 'p-2': isSmall, 'p-3': !isSmall, 'bg-500' : rtc.state?.selfSession.raisingHand }"
|
||||
t-att-aria-label="handText"
|
||||
t-att-title="handText"
|
||||
t-on-click="onClickRaiseHand">
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
</small>
|
||||
</span>
|
||||
<div class="o-mail-CallParticipantCard-overlay position-absolute top-0 end-0 d-flex flex-row-reverse">
|
||||
<span t-if="rtcSession.isRaisingHand" class="d-flex flex-column justify-content-center me-1 rounded-circle bg-500" t-att-class="{'o-minimized p-1': props.minimized, 'p-2': !props.minimized }" title="raising hand" aria-label="raising hand">
|
||||
<span t-if="rtcSession.raisingHand" class="d-flex flex-column justify-content-center me-1 rounded-circle bg-500" t-att-class="{'o-minimized p-1': props.minimized, 'p-2': !props.minimized }" title="raising hand" aria-label="raising hand">
|
||||
<i class="fa fa-hand-paper-o"/>
|
||||
</span>
|
||||
<span t-if="rtcSession.isSelfMuted and !rtcSession.isDeaf" class="d-flex flex-column justify-content-center me-1 rounded-circle bg-900" t-att-class="{'o-minimized p-1': props.minimized, 'p-2': !props.minimized }" title="muted" aria-label="muted">
|
||||
|
||||
@@ -440,10 +440,12 @@ export class Rtc {
|
||||
this.disconnect(session);
|
||||
break;
|
||||
case "raise_hand":
|
||||
Object.assign(session, { isRaisingHand: payload.active });
|
||||
Object.assign(session, {
|
||||
raisingHand: payload.active ? new Date() : undefined,
|
||||
});
|
||||
// eslint-disable-next-line no-case-declarations
|
||||
const notificationId = "raise_hand_" + session.id;
|
||||
if (session.isRaisingHand) {
|
||||
if (session.raisingHand) {
|
||||
this.addCallNotification({
|
||||
id: notificationId,
|
||||
text: sprintf(_t("%s raised a hand"), session.name),
|
||||
@@ -691,7 +693,7 @@ export class Rtc {
|
||||
},
|
||||
});
|
||||
await this.notify([session], "raise_hand", {
|
||||
active: this.state.selfSession.isRaisingHand,
|
||||
active: Boolean(this.state.selfSession.raisingHand),
|
||||
});
|
||||
} catch (e) {
|
||||
if (!(e instanceof DOMException) || e.name !== "OperationError") {
|
||||
@@ -929,10 +931,10 @@ export class Rtc {
|
||||
delete session.packetsSent;
|
||||
delete session.dtlsState;
|
||||
delete session.iceState;
|
||||
delete session.raisingHand;
|
||||
delete session.logStep;
|
||||
delete session.audioError;
|
||||
delete session.videoError;
|
||||
session.isRaisingHand = false;
|
||||
session.isTalking = false;
|
||||
this.removeVideoFromSession(session);
|
||||
session.dataChannel?.close();
|
||||
@@ -1057,15 +1059,15 @@ export class Rtc {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Boolean} isRaisingHand
|
||||
* @param {Boolean} raise
|
||||
*/
|
||||
async raiseHand(isRaisingHand) {
|
||||
async raiseHand(raise) {
|
||||
if (!this.state.selfSession || !this.state.channel) {
|
||||
return;
|
||||
}
|
||||
this.state.selfSession.isRaisingHand = isRaisingHand;
|
||||
this.state.selfSession.raisingHand = raise ? new Date() : undefined;
|
||||
await this.notify(Object.values(this.state.channel.rtcSessions), "raise_hand", {
|
||||
active: this.state.selfSession.isRaisingHand,
|
||||
active: this.state.selfSession.raisingHand,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -20,11 +20,12 @@ export class RtcSession {
|
||||
dataChannel;
|
||||
audioError;
|
||||
videoError;
|
||||
isRaisingHand;
|
||||
isTalking;
|
||||
localVolume;
|
||||
/** @type {RTCPeerConnection} */
|
||||
peerConnection;
|
||||
/** @type {Date|undefined} */
|
||||
raisingHand;
|
||||
videoComponentCount = 0;
|
||||
/** @type {MediaStream} */
|
||||
videoStream;
|
||||
|
||||
Reference in New Issue
Block a user