Fix the state shown for call in rooms (#10833)

* Fix the state shown for call in rooms

We split out a separate state for 'missed' separate to 'ended' which
caused confusion as the state got set to this when it shouldn't have,
so calls that wouldn't have been shown as missed were.

Remove the csutom call state and just have the missed state as a
variant of the ended state. Re-order the if clauses so they hit the
right ones. Also don't pass the callState variable into renderContent()
which is a class method and so has access to the same info anyway.

* Fix test

* i18n (reorder only)

* Fix test

* Fix types

* Add test for legacy call event tile
This commit is contained in:
David Baker 2023-05-15 09:37:40 +01:00 committed by GitHub
parent 5988bb9a68
commit 1aa9860743
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 163 additions and 43 deletions

View file

@ -37,10 +37,6 @@ const CONNECTING_STATES = [
const SUPPORTED_STATES = [CallState.Connected, CallState.Ringing, CallState.Ended];
export enum CustomCallState {
Missed = "missed",
}
const isCallEventType = (eventType: string): boolean =>
eventType.startsWith("m.call.") || eventType.startsWith("org.matrix.call.");
@ -73,7 +69,7 @@ export function buildLegacyCallEventGroupers(
export default class LegacyCallEventGrouper extends EventEmitter {
private events: Set<MatrixEvent> = new Set<MatrixEvent>();
private call: MatrixCall | null = null;
public state?: CallState | CustomCallState;
public state?: CallState;
public constructor() {
super();
@ -130,8 +126,11 @@ export default class LegacyCallEventGrouper extends EventEmitter {
/**
* Returns true if there are only events from the other side - we missed the call
*/
private get callWasMissed(): boolean {
return ![...this.events].some((event) => event.sender?.userId === MatrixClientPeg.get().getUserId());
public get callWasMissed(): boolean {
return (
this.state === CallState.Ended &&
![...this.events].some((event) => event.sender?.userId === MatrixClientPeg.get().getUserId())
);
}
private get callId(): string | undefined {
@ -188,10 +187,13 @@ export default class LegacyCallEventGrouper extends EventEmitter {
} else if (this.call && SUPPORTED_STATES.includes(this.call.state)) {
this.state = this.call.state;
} else {
if (this.callWasMissed) this.state = CustomCallState.Missed;
else if (this.reject) this.state = CallState.Ended;
else if (this.hangup) this.state = CallState.Ended;
else if (this.invite && this.call) this.state = CallState.Connecting;
if (this.reject) {
this.state = CallState.Ended;
} else if (this.hangup) {
this.state = CallState.Ended;
} else if (this.invite && this.call) {
this.state = CallState.Connecting;
}
}
this.emit(LegacyCallEventGrouperEvent.StateChanged, this.state);
};

View file

@ -21,10 +21,7 @@ import classNames from "classnames";
import { _t } from "../../../languageHandler";
import MemberAvatar from "../avatars/MemberAvatar";
import LegacyCallEventGrouper, {
LegacyCallEventGrouperEvent,
CustomCallState,
} from "../../structures/LegacyCallEventGrouper";
import LegacyCallEventGrouper, { LegacyCallEventGrouperEvent } from "../../structures/LegacyCallEventGrouper";
import AccessibleButton from "../elements/AccessibleButton";
import InfoTooltip, { InfoTooltipKind } from "../elements/InfoTooltip";
import AccessibleTooltipButton from "../elements/AccessibleTooltipButton";
@ -40,7 +37,7 @@ interface IProps {
}
interface IState {
callState: CallState | CustomCallState;
callState?: CallState;
silenced: boolean;
narrow: boolean;
length: number;
@ -125,8 +122,8 @@ export default class LegacyCallEvent extends React.PureComponent<IProps, IState>
);
}
private renderContent(state: CallState | CustomCallState): JSX.Element {
if (state === CallState.Ringing) {
private renderContent(): JSX.Element {
if (this.state.callState === CallState.Ringing) {
let silenceIcon;
if (!this.state.narrow) {
silenceIcon = this.renderSilenceIcon();
@ -153,7 +150,7 @@ export default class LegacyCallEvent extends React.PureComponent<IProps, IState>
</div>
);
}
if (state === CallState.Ended) {
if (this.state.callState === CallState.Ended) {
const hangupReason = this.props.callEventGrouper.hangupReason;
const gotRejected = this.props.callEventGrouper.gotRejected;
@ -165,6 +162,21 @@ export default class LegacyCallEvent extends React.PureComponent<IProps, IState>
{this.props.timestamp}
</div>
);
} else if (hangupReason === CallErrorCode.AnsweredElsewhere) {
return (
<div className="mx_LegacyCallEvent_content">
{_t("Answered elsewhere")}
{this.props.timestamp}
</div>
);
} else if (this.props.callEventGrouper.callWasMissed) {
return (
<div className="mx_LegacyCallEvent_content">
{_t("Missed call")}
{this.renderCallBackButton(_t("Call back"))}
{this.props.timestamp}
</div>
);
} else if (!hangupReason || [CallErrorCode.UserHangup, "user hangup"].includes(hangupReason)) {
// workaround for https://github.com/vector-im/element-web/issues/5178
// it seems Android randomly sets a reason of "user hangup" which is
@ -191,13 +203,6 @@ export default class LegacyCallEvent extends React.PureComponent<IProps, IState>
{this.props.timestamp}
</div>
);
} else if (hangupReason === CallErrorCode.AnsweredElsewhere) {
return (
<div className="mx_LegacyCallEvent_content">
{_t("Answered elsewhere")}
{this.props.timestamp}
</div>
);
}
let reason;
@ -234,7 +239,7 @@ export default class LegacyCallEvent extends React.PureComponent<IProps, IState>
</div>
);
}
if (state === CallState.Connected) {
if (this.state.callState === CallState.Connected) {
return (
<div className="mx_LegacyCallEvent_content">
<Clock seconds={this.state.length} aria-live="off" />
@ -242,7 +247,7 @@ export default class LegacyCallEvent extends React.PureComponent<IProps, IState>
</div>
);
}
if (state === CallState.Connecting) {
if (this.state.callState === CallState.Connecting) {
return (
<div className="mx_LegacyCallEvent_content">
{_t("Connecting")}
@ -250,15 +255,6 @@ export default class LegacyCallEvent extends React.PureComponent<IProps, IState>
</div>
);
}
if (state === CustomCallState.Missed) {
return (
<div className="mx_LegacyCallEvent_content">
{_t("Missed call")}
{this.renderCallBackButton(_t("Call back"))}
{this.props.timestamp}
</div>
);
}
return (
<div className="mx_LegacyCallEvent_content">
@ -275,12 +271,12 @@ export default class LegacyCallEvent extends React.PureComponent<IProps, IState>
const callType = isVoice ? _t("Voice call") : _t("Video call");
const callState = this.state.callState;
const hangupReason = this.props.callEventGrouper.hangupReason;
const content = this.renderContent(callState);
const content = this.renderContent();
const className = classNames("mx_LegacyCallEvent", {
mx_LegacyCallEvent_voice: isVoice,
mx_LegacyCallEvent_video: !isVoice,
mx_LegacyCallEvent_narrow: this.state.narrow,
mx_LegacyCallEvent_missed: callState === CustomCallState.Missed,
mx_LegacyCallEvent_missed: this.props.callEventGrouper.callWasMissed,
mx_LegacyCallEvent_noAnswer: callState === CallState.Ended && hangupReason === CallErrorCode.InviteTimeout,
mx_LegacyCallEvent_rejected: callState === CallState.Ended && this.props.callEventGrouper.gotRejected,
});

View file

@ -2402,15 +2402,15 @@
"Go": "Go",
"Call declined": "Call declined",
"Call back": "Call back",
"No answer": "No answer",
"Answered elsewhere": "Answered elsewhere",
"Missed call": "Missed call",
"No answer": "No answer",
"Could not connect media": "Could not connect media",
"Connection failed": "Connection failed",
"Their device couldn't start the camera or microphone": "Their device couldn't start the camera or microphone",
"An unknown error occurred": "An unknown error occurred",
"Unknown failure: %(reason)s": "Unknown failure: %(reason)s",
"Retry": "Retry",
"Missed call": "Missed call",
"The call is in an unknown state!": "The call is in an unknown state!",
"Error processing audio message": "Error processing audio message",
"View live location": "View live location",