Skip to content
This repository has been archived by the owner on Sep 11, 2024. It is now read-only.

Commit

Permalink
Add a way to maximize/pin widget from the PiP view (#7672)
Browse files Browse the repository at this point in the history
  • Loading branch information
SimonBrandner committed May 5, 2022
1 parent 1a0af54 commit c79596c
Show file tree
Hide file tree
Showing 5 changed files with 112 additions and 46 deletions.
24 changes: 16 additions & 8 deletions res/css/views/voip/_CallViewHeader.scss
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ limitations under the License.

.mx_CallViewHeader_controls {
margin-left: auto;
display: flex;
gap: 5px;
}

.mx_CallViewHeader_button {
Expand All @@ -63,17 +65,23 @@ limitations under the License.
mask-size: contain;
mask-position: center;
}
}

.mx_CallViewHeader_button_fullscreen {
&::before {
mask-image: url('$(res)/img/element-icons/call/fullscreen.svg');
&.mx_CallViewHeader_button_fullscreen {
&::before {
mask-image: url('$(res)/img/element-icons/call/fullscreen.svg');
}
}
}

.mx_CallViewHeader_button_expand {
&::before {
mask-image: url('$(res)/img/element-icons/call/expand.svg');
&.mx_CallViewHeader_button_pin {
&::before {
mask-image: url('$(res)/img/element-icons/room/pin-upright.svg');
}
}

&.mx_CallViewHeader_button_expand {
&::before {
mask-image: url('$(res)/img/element-icons/call/expand.svg');
}
}
}

Expand Down
8 changes: 8 additions & 0 deletions src/components/views/voip/CallView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,13 @@ export default class CallView extends React.Component<IProps, IState> {
return { primary, sidebar };
}

private onMaximizeClick = (): void => {
dis.dispatch({
action: 'video_fullscreen',
fullscreen: true,
});
};

private onMicMuteClick = async (): Promise<void> => {
const newVal = !this.state.micMuted;
this.setState({ micMuted: await this.props.call.setMicrophoneMuted(newVal) });
Expand Down Expand Up @@ -614,6 +621,7 @@ export default class CallView extends React.Component<IProps, IState> {
onPipMouseDown={onMouseDownOnHeader}
pipMode={pipMode}
callRooms={[callRoom, secCallRoom]}
onMaximize={this.onMaximizeClick}
/>
<div className="mx_CallView_content_wrapper" ref={this.contentWrapperRef}>
{ this.renderToast() }
Expand Down
69 changes: 35 additions & 34 deletions src/components/views/voip/CallView/CallViewHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,50 +19,39 @@ import React from 'react';

import { _t } from '../../../../languageHandler';
import RoomAvatar from '../../avatars/RoomAvatar';
import dis from '../../../../dispatcher/dispatcher';
import { Action } from '../../../../dispatcher/actions';
import AccessibleTooltipButton from '../../elements/AccessibleTooltipButton';
import { ViewRoomPayload } from "../../../../dispatcher/payloads/ViewRoomPayload";

interface CallViewHeaderProps {
pipMode: boolean;
callRooms?: Room[];
onPipMouseDown: (event: React.MouseEvent<Element, MouseEvent>) => void;
interface CallControlsProps {
onExpand?: () => void;
onPin?: () => void;
onMaximize?: () => void;
}

const onFullscreenClick = () => {
dis.dispatch({
action: 'video_fullscreen',
fullscreen: true,
});
};

const onExpandClick = (roomId: string) => {
dis.dispatch<ViewRoomPayload>({
action: Action.ViewRoom,
room_id: roomId,
metricsTrigger: "WebFloatingCallWindow",
});
};

type CallControlsProps = Pick<CallViewHeaderProps, 'pipMode'> & {
roomId: string;
};
const CallViewHeaderControls: React.FC<CallControlsProps> = ({ pipMode = false, roomId }) => {
const CallViewHeaderControls: React.FC<CallControlsProps> = ({ onExpand, onPin, onMaximize }) => {
return <div className="mx_CallViewHeader_controls">
{ !pipMode && <AccessibleTooltipButton
{ onMaximize && <AccessibleTooltipButton
className="mx_CallViewHeader_button mx_CallViewHeader_button_fullscreen"
onClick={onFullscreenClick}
onClick={onMaximize}
title={_t("Fill Screen")}
/> }
{ pipMode && <AccessibleTooltipButton
{ onPin && <AccessibleTooltipButton
className="mx_CallViewHeader_button mx_CallViewHeader_button_pin"
onClick={onPin}
title={_t("Pin")}
/> }
{ onExpand && <AccessibleTooltipButton
className="mx_CallViewHeader_button mx_CallViewHeader_button_expand"
onClick={() => onExpandClick(roomId)}
onClick={onExpand}
title={_t("Return to call")}
/> }
</div>;
};
const SecondaryCallInfo: React.FC<{ callRoom: Room }> = ({ callRoom }) => {

interface ISecondaryCallInfoProps {
callRoom: Room;
}

const SecondaryCallInfo: React.FC<ISecondaryCallInfoProps> = ({ callRoom }) => {
return <span className="mx_CallViewHeader_secondaryCallInfo">
<RoomAvatar room={callRoom} height={16} width={16} />
<span className="mx_CallView_secondaryCall_roomName">
Expand All @@ -71,19 +60,31 @@ const SecondaryCallInfo: React.FC<{ callRoom: Room }> = ({ callRoom }) => {
</span>;
};

interface CallViewHeaderProps {
pipMode: boolean;
callRooms?: Room[];
onPipMouseDown: (event: React.MouseEvent<Element, MouseEvent>) => void;
onExpand?: () => void;
onPin?: () => void;
onMaximize?: () => void;
}

const CallViewHeader: React.FC<CallViewHeaderProps> = ({
pipMode = false,
callRooms = [],
onPipMouseDown,
onExpand,
onPin,
onMaximize,
}) => {
const [callRoom, onHoldCallRoom] = callRooms;
const { roomId, name: callRoomName } = callRoom;
const callRoomName = callRoom.name;

if (!pipMode) {
return <div className="mx_CallViewHeader">
<div className="mx_CallViewHeader_icon" />
<span className="mx_CallViewHeader_text">{ _t("Call") }</span>
<CallViewHeaderControls roomId={roomId} pipMode={pipMode} />
<CallViewHeaderControls onMaximize={onMaximize} />
</div>;
}
return (
Expand All @@ -96,7 +97,7 @@ const CallViewHeader: React.FC<CallViewHeaderProps> = ({
<div className="mx_CallViewHeader_roomName">{ callRoomName }</div>
{ onHoldCallRoom && <SecondaryCallInfo callRoom={onHoldCallRoom} /> }
</div>
<CallViewHeaderControls roomId={roomId} pipMode={pipMode} />
<CallViewHeaderControls onExpand={onExpand} onPin={onPin} onMaximize={onMaximize} />
</div>
);
};
Expand Down
55 changes: 52 additions & 3 deletions src/components/views/voip/PipView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import { CallEvent, CallState, MatrixCall } from 'matrix-js-sdk/src/webrtc/call'
import { EventSubscription } from 'fbemitter';
import { logger } from "matrix-js-sdk/src/logger";
import classNames from 'classnames';
import { Room } from "matrix-js-sdk/src/models/room";

import CallView from "./CallView";
import { RoomViewStore } from '../../../stores/RoomViewStore';
Expand All @@ -29,9 +30,10 @@ import { MatrixClientPeg } from '../../../MatrixClientPeg';
import PictureInPictureDragger from './PictureInPictureDragger';
import dis from '../../../dispatcher/dispatcher';
import { Action } from "../../../dispatcher/actions";
import { WidgetLayoutStore } from '../../../stores/widgets/WidgetLayoutStore';
import { Container, WidgetLayoutStore } from '../../../stores/widgets/WidgetLayoutStore';
import CallViewHeader from './CallView/CallViewHeader';
import ActiveWidgetStore, { ActiveWidgetStoreEvent } from '../../../stores/ActiveWidgetStore';
import WidgetStore, { IApp } from "../../../stores/WidgetStore";
import { ViewRoomPayload } from "../../../dispatcher/payloads/ViewRoomPayload";

const SHOW_CALL_IN_STATES = [
Expand Down Expand Up @@ -64,6 +66,16 @@ interface IState {
moving: boolean;
}

const getRoomAndAppForWidget = (widgetId: string, roomId: string): [Room, IApp] => {
if (!widgetId) return;
if (!roomId) return;

const room = MatrixClientPeg.get().getRoom(roomId);
const app = WidgetStore.instance.getApps(roomId).find((app) => app.id === widgetId);

return [room, app];
};

// Splits a list of calls into one 'primary' one and a list
// (which should be a single element) of other calls.
// The primary will be the one not on hold, or an arbitrary one
Expand Down Expand Up @@ -232,6 +244,38 @@ export default class PipView extends React.Component<IProps, IState> {
}
};

private onMaximize = (): void => {
const widgetId = this.state.persistentWidgetId;
const roomId = this.state.persistentRoomId;

if (this.state.showWidgetInPip && widgetId && roomId) {
const [room, app] = getRoomAndAppForWidget(widgetId, roomId);
WidgetLayoutStore.instance.moveToContainer(room, app, Container.Center);
} else {
dis.dispatch({
action: 'video_fullscreen',
fullscreen: true,
});
}
};

private onPin = (): void => {
if (!this.state.showWidgetInPip) return;

const [room, app] = getRoomAndAppForWidget(this.state.persistentWidgetId, this.state.persistentRoomId);
WidgetLayoutStore.instance.moveToContainer(room, app, Container.Top);
};

private onExpand = (): void => {
const widgetId = this.state.persistentWidgetId;
if (!widgetId || !this.state.showWidgetInPip) return;

dis.dispatch({
action: Action.ViewRoom,
room_id: this.state.persistentRoomId,
});
};

// Accepts a persistentWidgetId to be able to skip awaiting the setState for persistentWidgetId
public updateShowWidgetInPip(
persistentWidgetId = this.state.persistentWidgetId,
Expand Down Expand Up @@ -276,18 +320,23 @@ export default class PipView extends React.Component<IProps, IState> {
mx_CallView_pip: pipMode,
mx_CallView_large: !pipMode,
});
const roomForWidget = MatrixClientPeg.get().getRoom(this.state.persistentRoomId);
const roomId = this.state.persistentRoomId;
const roomForWidget = MatrixClientPeg.get().getRoom(roomId);
const viewingCallRoom = this.state.viewedRoomId === roomId;

pipContent = ({ onStartMoving, _onResize }) =>
<div className={pipViewClasses}>
<CallViewHeader
onPipMouseDown={(event) => { onStartMoving(event); this.onStartMoving.bind(this)(); }}
pipMode={pipMode}
callRooms={[roomForWidget]}
onExpand={!viewingCallRoom && this.onExpand}
onPin={viewingCallRoom && this.onPin}
onMaximize={viewingCallRoom && this.onMaximize}
/>
<PersistentApp
persistentWidgetId={this.state.persistentWidgetId}
persistentRoomId={this.state.persistentRoomId}
persistentRoomId={roomId}
pointerEvents={this.state.moving ? 'none' : undefined}
/>
</div>;
Expand Down
2 changes: 1 addition & 1 deletion src/i18n/strings/en_EN.json
Original file line number Diff line number Diff line change
Expand Up @@ -1045,6 +1045,7 @@
"More": "More",
"Hangup": "Hangup",
"Fill Screen": "Fill Screen",
"Pin": "Pin",
"Return to call": "Return to call",
"%(name)s on hold": "%(name)s on hold",
"Call": "Call",
Expand Down Expand Up @@ -1128,7 +1129,6 @@
"Anchor": "Anchor",
"Headphones": "Headphones",
"Folder": "Folder",
"Pin": "Pin",
"Your server isn't responding to some <a>requests</a>.": "Your server isn't responding to some <a>requests</a>.",
"Decline (%(counter)s)": "Decline (%(counter)s)",
"Accept <policyLink /> to continue:": "Accept <policyLink /> to continue:",
Expand Down

0 comments on commit c79596c

Please sign in to comment.