Merge remote-tracking branch 'upstream/develop' into fix/17130/draggable-pip

Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>
This commit is contained in:
Šimon Brandner 2021-07-09 08:26:19 +02:00
commit 91d208d514
No known key found for this signature in database
GPG key ID: 9760693FDD98A790
802 changed files with 12931 additions and 11005 deletions

View file

@ -14,32 +14,38 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import React, {createRef} from 'react';
import React, { createRef } from 'react';
import { CallFeed, CallFeedEvent } from 'matrix-js-sdk/src/webrtc/callFeed';
import { logger } from 'matrix-js-sdk/src/logger';
import CallMediaHandler from "../../../CallMediaHandler";
import MediaDeviceHandler, { MediaDeviceHandlerEvent } from "../../../MediaDeviceHandler";
interface IProps {
feed: CallFeed,
feed: CallFeed;
}
export default class AudioFeed extends React.Component<IProps> {
private element = createRef<HTMLAudioElement>();
componentDidMount() {
MediaDeviceHandler.instance.addListener(
MediaDeviceHandlerEvent.AudioOutputChanged,
this.onAudioOutputChanged,
);
this.props.feed.addListener(CallFeedEvent.NewStream, this.onNewStream);
this.playMedia();
}
componentWillUnmount() {
MediaDeviceHandler.instance.removeListener(
MediaDeviceHandlerEvent.AudioOutputChanged,
this.onAudioOutputChanged,
);
this.props.feed.removeListener(CallFeedEvent.NewStream, this.onNewStream);
this.stopMedia();
}
private playMedia() {
private onAudioOutputChanged = (audioOutput: string) => {
const element = this.element.current;
const audioOutput = CallMediaHandler.getAudioOutput();
if (audioOutput) {
try {
// This seems quite unreliable in Chrome, although I haven't yet managed to make a jsfiddle where
@ -52,7 +58,11 @@ export default class AudioFeed extends React.Component<IProps> {
logger.warn("Couldn't set requested audio output device: using default", e);
}
}
};
private playMedia() {
const element = this.element.current;
this.onAudioOutputChanged(MediaDeviceHandler.getAudioOutput());
element.muted = false;
element.srcObject = this.props.feed.stream;
element.autoplay = true;
@ -67,7 +77,7 @@ export default class AudioFeed extends React.Component<IProps> {
// should serialise the ones that need to be serialised but then be able to interrupt
// them with another load() which will cancel the pending one, but since we don't call
// load() explicitly, it shouldn't be a problem. - Dave
element.play()
element.play();
} catch (e) {
logger.info("Failed to play media element with feed", this.props.feed, e);
}

View file

@ -15,7 +15,7 @@ limitations under the License.
*/
import React from "react";
import AudioFeed from "./AudioFeed"
import AudioFeed from "./AudioFeed";
import { CallEvent, MatrixCall } from "matrix-js-sdk/src/webrtc/call";
import { CallFeed } from "matrix-js-sdk/src/webrtc/callFeed";
@ -48,7 +48,7 @@ export default class AudioFeedArrayForCall extends React.Component<IProps, IStat
this.setState({
feeds: this.props.call.getRemoteFeeds(),
});
}
};
render() {
return this.state.feeds.map((feed, i) => {

View file

@ -17,7 +17,7 @@ limitations under the License.
import React from 'react';
import IncomingCallBox from './IncomingCallBox';
import CallPreview from './CallPreview';
import {replaceableComponent} from "../../../utils/replaceableComponent";
import { replaceableComponent } from "../../../utils/replaceableComponent";
interface IProps {

View file

@ -26,7 +26,7 @@ import PersistentApp from "../elements/PersistentApp";
import SettingsStore from "../../../settings/SettingsStore";
import { CallEvent, CallState, MatrixCall } from 'matrix-js-sdk/src/webrtc/call';
import { MatrixClientPeg } from '../../../MatrixClientPeg';
import {replaceableComponent} from "../../../utils/replaceableComponent";
import { replaceableComponent } from "../../../utils/replaceableComponent";
import UIStore from '../../../stores/UIStore';
import { lerp } from '../../../utils/AnimationUtils';
@ -41,7 +41,7 @@ const PADDING = {
bottom: 58,
left: 76,
right: 8,
}
};
const SHOW_CALL_IN_STATES = [
CallState.Connected,
@ -52,7 +52,6 @@ const SHOW_CALL_IN_STATES = [
CallState.WaitLocalMedia,
];
interface IProps {
}
@ -177,7 +176,7 @@ export default class CallPreview extends React.Component<IProps, IState> {
translationY: lerp(this.state.translationY, this.desiredTranslationY, amt),
});
requestAnimationFrame(this.animationCallback);
}
};
private setTranslation(inTranslationX: number, inTranslationY: number) {
const width = this.callViewWrapper.current?.clientWidth || PIP_VIEW_WIDTH;
@ -234,7 +233,7 @@ export default class CallPreview extends React.Component<IProps, IState> {
// We start animating here because we want the PiP to move when we're
// resizing the window
requestAnimationFrame(this.animationCallback);
}
};
private onRoomViewStoreUpdate = (payload) => {
if (RoomViewStore.getRoomId() === this.state.roomId) return;

View file

@ -18,27 +18,27 @@ limitations under the License.
import React, { createRef, CSSProperties } from 'react';
import dis from '../../../dispatcher/dispatcher';
import CallHandler from '../../../CallHandler';
import {MatrixClientPeg} from '../../../MatrixClientPeg';
import { MatrixClientPeg } from '../../../MatrixClientPeg';
import { _t, _td } from '../../../languageHandler';
import VideoFeed from './VideoFeed';
import RoomAvatar from "../avatars/RoomAvatar";
import { CallState, CallType, MatrixCall, CallEvent } from 'matrix-js-sdk/src/webrtc/call';
import classNames from 'classnames';
import AccessibleButton from '../elements/AccessibleButton';
import {isOnlyCtrlOrCmdKeyEvent, Key} from '../../../Keyboard';
import {alwaysAboveLeftOf, alwaysAboveRightOf, ChevronFace, ContextMenuButton} from '../../structures/ContextMenu';
import { isOnlyCtrlOrCmdKeyEvent, Key } from '../../../Keyboard';
import { alwaysAboveLeftOf, alwaysAboveRightOf, ChevronFace, ContextMenuButton } from '../../structures/ContextMenu';
import CallContextMenu from '../context_menus/CallContextMenu';
import { avatarUrlForMember } from '../../../Avatar';
import DialpadContextMenu from '../context_menus/DialpadContextMenu';
import { CallFeed } from 'matrix-js-sdk/src/webrtc/callFeed';
import {replaceableComponent} from "../../../utils/replaceableComponent";
import { replaceableComponent } from "../../../utils/replaceableComponent";
interface IProps {
// The call for us to display
call: MatrixCall,
call: MatrixCall;
// Another ongoing call to display information about
secondaryCall?: MatrixCall,
secondaryCall?: MatrixCall;
// a callback which is called when the content in the CallView changes
// in a way that is likely to cause a resize.
@ -55,15 +55,15 @@ interface IProps {
}
interface IState {
isLocalOnHold: boolean,
isRemoteOnHold: boolean,
micMuted: boolean,
vidMuted: boolean,
callState: CallState,
controlsVisible: boolean,
showMoreMenu: boolean,
showDialpad: boolean,
feeds: CallFeed[],
isLocalOnHold: boolean;
isRemoteOnHold: boolean;
micMuted: boolean;
vidMuted: boolean;
callState: CallState;
controlsVisible: boolean;
showMoreMenu: boolean;
showDialpad: boolean;
feeds: CallFeed[];
}
function getFullScreenElement() {
@ -120,7 +120,7 @@ export default class CallView extends React.Component<IProps, IState> {
showMoreMenu: false,
showDialpad: false,
feeds: this.props.call.getFeeds(),
}
};
this.updateCallListeners(null, this.props.call);
}
@ -194,7 +194,7 @@ export default class CallView extends React.Component<IProps, IState> {
};
private onFeedsChanged = (newFeeds: Array<CallFeed>) => {
this.setState({feeds: newFeeds});
this.setState({ feeds: newFeeds });
};
private onCallLocalHoldUnhold = () => {
@ -231,11 +231,11 @@ export default class CallView extends React.Component<IProps, IState> {
this.setState({
controlsVisible: false,
});
}
};
private onMouseMove = () => {
this.showControls();
}
};
private showControls() {
if (this.state.showMoreMenu || this.state.showDialpad) return;
@ -272,21 +272,21 @@ export default class CallView extends React.Component<IProps, IState> {
showDialpad: false,
});
}
}
};
private onMicMuteClick = () => {
const newVal = !this.state.micMuted;
this.props.call.setMicrophoneMuted(newVal);
this.setState({micMuted: newVal});
}
this.setState({ micMuted: newVal });
};
private onVidMuteClick = () => {
const newVal = !this.state.vidMuted;
this.props.call.setLocalVideoMuted(newVal);
this.setState({vidMuted: newVal});
}
this.setState({ vidMuted: newVal });
};
private onMoreClick = () => {
if (this.controlsHideTimer) {
@ -298,21 +298,21 @@ export default class CallView extends React.Component<IProps, IState> {
showMoreMenu: true,
controlsVisible: true,
});
}
};
private closeDialpad = () => {
this.setState({
showDialpad: false,
});
this.controlsHideTimer = window.setTimeout(this.onControlsHideTimer, CONTROLS_HIDE_DELAY);
}
};
private closeContextMenu = () => {
this.setState({
showMoreMenu: false,
});
this.controlsHideTimer = window.setTimeout(this.onControlsHideTimer, CONTROLS_HIDE_DELAY);
}
};
// we register global shortcuts here, they *must not conflict* with local shortcuts elsewhere or both will fire
// Note that this assumes we always have a CallView on screen at any given time
@ -353,7 +353,7 @@ export default class CallView extends React.Component<IProps, IState> {
action: 'view_room',
room_id: userFacingRoomId,
});
}
};
private onSecondaryRoomAvatarClick = () => {
const userFacingRoomId = CallHandler.sharedInstance().roomIdForCall(this.props.secondaryCall);
@ -362,17 +362,17 @@ export default class CallView extends React.Component<IProps, IState> {
action: 'view_room',
room_id: userFacingRoomId,
});
}
};
private onCallResumeClick = () => {
const userFacingRoomId = CallHandler.sharedInstance().roomIdForCall(this.props.call);
CallHandler.sharedInstance().setActiveCallRoomId(userFacingRoomId);
}
};
private onTransferClick = () => {
const transfereeCall = CallHandler.sharedInstance().getTransfereeForCallId(this.props.call.callId);
this.props.call.transferToCall(transfereeCall);
}
};
public render() {
const client = MatrixClientPeg.get();
@ -573,7 +573,7 @@ export default class CallView extends React.Component<IProps, IState> {
<div className="mx_CallView_voice_avatarsContainer">
<div
className="mx_CallView_voice_avatarContainer"
style={{width: avatarSize, height: avatarSize}}
style={{ width: avatarSize, height: avatarSize }}
>
<RoomAvatar
room={callRoom}
@ -617,7 +617,7 @@ export default class CallView extends React.Component<IProps, IState> {
contentView = <div className={classes} onMouseMove={this.onMouseMove}>
{feeds}
<div className="mx_CallView_voice_avatarsContainer">
<div className="mx_CallView_voice_avatarContainer" style={{width: avatarSize, height: avatarSize}}>
<div className="mx_CallView_voice_avatarContainer" style={{ width: avatarSize, height: avatarSize }}>
<RoomAvatar
room={callRoom}
height={avatarSize}

View file

@ -19,22 +19,22 @@ import React from 'react';
import CallHandler, { CallHandlerEvent } from '../../../CallHandler';
import CallView from './CallView';
import dis from '../../../dispatcher/dispatcher';
import {Resizable} from "re-resizable";
import { Resizable } from "re-resizable";
import ResizeNotifier from "../../../utils/ResizeNotifier";
import {replaceableComponent} from "../../../utils/replaceableComponent";
import { replaceableComponent } from "../../../utils/replaceableComponent";
interface IProps {
// What room we should display the call for
roomId: string,
roomId: string;
// maxHeight style attribute for the video panel
maxVideoHeight?: number;
resizeNotifier: ResizeNotifier,
resizeNotifier: ResizeNotifier;
}
interface IState {
call: MatrixCall,
call: MatrixCall;
}
/*
@ -74,7 +74,7 @@ export default class CallViewForRoom extends React.Component<IProps, IState> {
private updateCall = () => {
const newCall = this.getCall();
if (newCall !== this.state.call) {
this.setState({call: newCall});
this.setState({ call: newCall });
}
};
@ -121,7 +121,7 @@ export default class CallViewForRoom extends React.Component<IProps, IState> {
onResize={this.onResize}
onResizeStop={this.onResizeStop}
className="mx_CallViewForRoom_ResizeWrapper"
handleClasses={{bottom: "mx_CallViewForRoom_ResizeHandle"}}
handleClasses={{ bottom: "mx_CallViewForRoom_ResizeHandle" }}
>
<CallView
call={this.state.call}

View file

@ -16,7 +16,7 @@ limitations under the License.
import * as React from "react";
import AccessibleButton from "../elements/AccessibleButton";
import {replaceableComponent} from "../../../utils/replaceableComponent";
import { replaceableComponent } from "../../../utils/replaceableComponent";
const BUTTONS = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '*', '0', '#'];
@ -35,7 +35,7 @@ interface IButtonProps {
class DialPadButton extends React.PureComponent<IButtonProps> {
onClick = () => {
this.props.onButtonPress(this.props.digit);
}
};
render() {
switch (this.props.kind) {

View file

@ -20,7 +20,7 @@ import AccessibleButton from "../elements/AccessibleButton";
import Field from "../elements/Field";
import DialPad from './DialPad';
import dis from '../../../dispatcher/dispatcher';
import {replaceableComponent} from "../../../utils/replaceableComponent";
import { replaceableComponent } from "../../../utils/replaceableComponent";
import { DialNumberPayload } from "../../../dispatcher/payloads/DialNumberPayload";
import { Action } from "../../../dispatcher/actions";
@ -38,30 +38,30 @@ export default class DialpadModal extends React.PureComponent<IProps, IState> {
super(props);
this.state = {
value: '',
}
};
}
onCancelClick = () => {
this.props.onFinished(false);
}
};
onChange = (ev) => {
this.setState({value: ev.target.value});
}
this.setState({ value: ev.target.value });
};
onFormSubmit = (ev) => {
ev.preventDefault();
this.onDialPress();
}
};
onDigitPress = (digit) => {
this.setState({value: this.state.value + digit});
}
this.setState({ value: this.state.value + digit });
};
onDeletePress = () => {
if (this.state.value.length === 0) return;
this.setState({value: this.state.value.slice(0, -1)});
}
this.setState({ value: this.state.value.slice(0, -1) });
};
onDialPress = async () => {
const payload: DialNumberPayload = {
@ -71,7 +71,7 @@ export default class DialpadModal extends React.PureComponent<IProps, IState> {
dis.dispatch(payload);
this.props.onFinished(true);
}
};
render() {
return <div className="mx_DialPadModal">

View file

@ -17,15 +17,15 @@ limitations under the License.
*/
import React from 'react';
import {MatrixClientPeg} from '../../../MatrixClientPeg';
import { MatrixClientPeg } from '../../../MatrixClientPeg';
import dis from '../../../dispatcher/dispatcher';
import { _t } from '../../../languageHandler';
import { ActionPayload } from '../../../dispatcher/payloads';
import CallHandler, { AudioID } from '../../../CallHandler';
import RoomAvatar from '../avatars/RoomAvatar';
import FormButton from '../elements/FormButton';
import AccessibleButton from '../elements/AccessibleButton';
import { CallState } from 'matrix-js-sdk/src/webrtc/call';
import {replaceableComponent} from "../../../utils/replaceableComponent";
import { replaceableComponent } from "../../../utils/replaceableComponent";
import AccessibleTooltipButton from '../elements/AccessibleTooltipButton';
import classNames from 'classnames';
@ -91,10 +91,10 @@ export default class IncomingCallBox extends React.Component<IProps, IState> {
private onSilenceClick: React.MouseEventHandler = (e) => {
e.stopPropagation();
const newState = !this.state.silenced
this.setState({silenced: newState});
const newState = !this.state.silenced;
this.setState({ silenced: newState });
newState ? CallHandler.sharedInstance().pause(AudioID.Ring) : CallHandler.sharedInstance().play(AudioID.Ring);
}
};
public render() {
if (!this.state.incomingCall) {
@ -143,21 +143,22 @@ export default class IncomingCallBox extends React.Component<IProps, IState> {
/>
</div>
<div className="mx_IncomingCallBox_buttons">
<FormButton
<AccessibleButton
className={"mx_IncomingCallBox_decline"}
onClick={this.onRejectClick}
kind="danger"
label={_t("Decline")}
/>
>
{ _t("Decline") }
</AccessibleButton>
<div className="mx_IncomingCallBox_spacer" />
<FormButton
<AccessibleButton
className={"mx_IncomingCallBox_accept"}
onClick={this.onAnswerClick}
kind="primary"
label={_t("Accept")}
/>
>
{ _t("Accept") }
</AccessibleButton>
</div>
</div>;
}
}

View file

@ -16,17 +16,17 @@ limitations under the License.
import classnames from 'classnames';
import { MatrixCall } from 'matrix-js-sdk/src/webrtc/call';
import React, {createRef} from 'react';
import React, { createRef } from 'react';
import SettingsStore from "../../../settings/SettingsStore";
import { CallFeed, CallFeedEvent } from 'matrix-js-sdk/src/webrtc/callFeed';
import { logger } from 'matrix-js-sdk/src/logger';
import MemberAvatar from "../avatars/MemberAvatar"
import {replaceableComponent} from "../../../utils/replaceableComponent";
import MemberAvatar from "../avatars/MemberAvatar";
import { replaceableComponent } from "../../../utils/replaceableComponent";
interface IProps {
call: MatrixCall,
call: MatrixCall;
feed: CallFeed,
feed: CallFeed;
// Whether this call view is for picture-in-picture mode
// otherwise, it's the larger call view when viewing the room the call is in.
@ -36,7 +36,7 @@ interface IProps {
// a callback which is called when the video element is resized
// due to a change in video metadata
onResize?: (e: Event) => void,
onResize?: (e: Event) => void;
}
interface IState {
@ -85,7 +85,7 @@ export default class VideoFeed extends React.Component<IProps, IState> {
// should serialise the ones that need to be serialised but then be able to interrupt
// them with another load() which will cancel the pending one, but since we don't call
// load() explicitly, it shouldn't be a problem. - Dave
element.play()
element.play();
} catch (e) {
logger.info("Failed to play media element with feed", this.props.feed, e);
}