diff --git a/src/components/views/context_menus/CallContextMenu.tsx b/src/components/views/context_menus/CallContextMenu.tsx index 336b72cebf..3557976326 100644 --- a/src/components/views/context_menus/CallContextMenu.tsx +++ b/src/components/views/context_menus/CallContextMenu.tsx @@ -20,6 +20,8 @@ import { _t } from '../../../languageHandler'; import { ContextMenu, IProps as IContextMenuProps, MenuItem } from '../../structures/ContextMenu'; import { MatrixCall } from 'matrix-js-sdk/src/webrtc/call'; import CallHandler from '../../../CallHandler'; +import InviteDialog, { KIND_CALL_TRANSFER } from '../dialogs/InviteDialog'; +import Modal from '../../../Modal'; interface IProps extends IContextMenuProps { call: MatrixCall; @@ -46,14 +48,30 @@ export default class CallContextMenu extends React.Component { this.props.onFinished(); } + onTransferClick = () => { + Modal.createTrackedDialog( + 'Transfer Call', '', InviteDialog, {kind: KIND_CALL_TRANSFER, call: this.props.call}, + /*className=*/null, /*isPriority=*/false, /*isStatic=*/true, + ); + this.props.onFinished(); + } + render() { const holdUnholdCaption = this.props.call.isRemoteOnHold() ? _t("Resume") : _t("Hold"); const handler = this.props.call.isRemoteOnHold() ? this.onUnholdClick : this.onHoldClick; + let transferItem; + if (this.props.call.opponentCanBeTransferred()) { + transferItem = + {_t("Transfer")} + ; + } + return {holdUnholdCaption} + {transferItem} ; } } diff --git a/src/components/views/dialogs/InviteDialog.tsx b/src/components/views/dialogs/InviteDialog.tsx index 8ccbbe473c..5b936e822c 100644 --- a/src/components/views/dialogs/InviteDialog.tsx +++ b/src/components/views/dialogs/InviteDialog.tsx @@ -41,12 +41,14 @@ import SettingsStore from "../../../settings/SettingsStore"; import {UIFeature} from "../../../settings/UIFeature"; import CountlyAnalytics from "../../../CountlyAnalytics"; import {Room} from "matrix-js-sdk/src/models/room"; +import { MatrixCall } from 'matrix-js-sdk/src/webrtc/call'; // we have a number of types defined from the Matrix spec which can't reasonably be altered here. /* eslint-disable camelcase */ export const KIND_DM = "dm"; export const KIND_INVITE = "invite"; +export const KIND_CALL_TRANSFER = "call_transfer"; const INITIAL_ROOMS_SHOWN = 3; // Number of rooms to show at first const INCREMENT_ROOMS_SHOWN = 5; // Number of rooms to add when 'show more' is clicked @@ -310,6 +312,9 @@ interface IInviteDialogProps { // The room ID this dialog is for. Only required for KIND_INVITE. roomId: string, + // The call to transfer. Only required for KIND_CALL_TRANSFER. + call: MatrixCall, + // Initial value to populate the filter with initialText: string, } @@ -345,6 +350,8 @@ export default class InviteDialog extends React.PureComponent { + this._convertFilter(); + const targets = this._convertFilter(); + const targetIds = targets.map(t => t.userId); + if (targetIds.length > 1) { + this.setState({ + errorText: _t("A call can only be transferred to a single user."), + }); + } + + this.setState({busy: true}); + try { + await this.props.call.transfer(targetIds[0]); + this.setState({busy: false}); + this.props.onFinished(); + } catch (e) { + this.setState({ + busy: false, + errorText: _t("Failed to transfer call"), + }); + } + }; + _onKeyDown = (e) => { if (this.state.busy) return; const value = e.target.value.trim(); @@ -1217,7 +1247,7 @@ export default class InviteDialog extends React.PureComponent 0 diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index c0939871e2..418dd2012c 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -2077,6 +2077,8 @@ "We couldn't create your DM. Please check the users you want to invite and try again.": "We couldn't create your DM. Please check the users you want to invite and try again.", "Something went wrong trying to invite the users.": "Something went wrong trying to invite the users.", "We couldn't invite those users. Please check the users you want to invite and try again.": "We couldn't invite those users. Please check the users you want to invite and try again.", + "A call can only be transferred to a single user.": "A call can only be transferred to a single user.", + "Failed to transfer call": "Failed to transfer call", "Failed to find the following users": "Failed to find the following users", "The following users might not exist or are invalid, and cannot be invited: %(csvNames)s": "The following users might not exist or are invalid, and cannot be invited: %(csvNames)s", "Recent Conversations": "Recent Conversations", @@ -2090,6 +2092,7 @@ "Go": "Go", "Invite someone using their name, email address, username (like ) or share this room.": "Invite someone using their name, email address, username (like ) or share this room.", "Invite someone using their name, username (like ) or share this room.": "Invite someone using their name, username (like ) or share this room.", + "Transfer": "Transfer", "a new master key signature": "a new master key signature", "a new cross-signing key signature": "a new cross-signing key signature", "a device cross-signing signature": "a device cross-signing signature",