Merge pull request #5710 from SimonBrandner/resizable-call-view

Resizable CallView
pull/21833/head
Travis Ralston 2021-04-07 11:02:46 -06:00 committed by GitHub
commit 6e6a26f86a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 103 additions and 35 deletions

View File

@ -250,6 +250,7 @@
@import "./views/voice_messages/_Waveform.scss"; @import "./views/voice_messages/_Waveform.scss";
@import "./views/voip/_CallContainer.scss"; @import "./views/voip/_CallContainer.scss";
@import "./views/voip/_CallView.scss"; @import "./views/voip/_CallView.scss";
@import "./views/voip/_CallViewForRoom.scss";
@import "./views/voip/_DialPad.scss"; @import "./views/voip/_DialPad.scss";
@import "./views/voip/_DialPadContextMenu.scss"; @import "./views/voip/_DialPadContextMenu.scss";
@import "./views/voip/_DialPadModal.scss"; @import "./views/voip/_DialPadModal.scss";

View File

@ -27,9 +27,12 @@ limitations under the License.
.mx_CallView_large { .mx_CallView_large {
padding-bottom: 10px; padding-bottom: 10px;
margin: 5px 5px 5px 18px; margin: 5px 5px 5px 18px;
display: flex;
flex-direction: column;
flex: 1;
.mx_CallView_voice { .mx_CallView_voice {
height: 360px; flex: 1;
} }
} }
@ -104,6 +107,7 @@ limitations under the License.
.mx_CallView_video { .mx_CallView_video {
width: 100%; width: 100%;
height: 100%;
position: relative; position: relative;
z-index: 30; z-index: 30;
border-radius: 8px; border-radius: 8px;
@ -177,6 +181,7 @@ limitations under the License.
flex-direction: row; flex-direction: row;
align-items: center; align-items: center;
justify-content: left; justify-content: left;
flex-shrink: 0;
} }
.mx_CallView_header_callType { .mx_CallView_header_callType {

View File

@ -0,0 +1,46 @@
/*
Copyright 2021 Šimon Brandner <simon.bra.ag@gmail.com>
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
.mx_CallViewForRoom {
overflow: hidden;
.mx_CallViewForRoom_ResizeWrapper {
display: flex;
margin-bottom: 8px;
&:hover .mx_CallViewForRoom_ResizeHandle {
// Need to use important to override element style attributes
// set by re-resizable
width: 100% !important;
display: flex;
justify-content: center;
&::after {
content: '';
margin-top: 3px;
border-radius: 4px;
height: 4px;
width: 100%;
max-width: 64px;
background-color: $primary-fg-color;
}
}
}
}

View File

@ -16,7 +16,7 @@ limitations under the License.
.mx_VideoFeed_remote { .mx_VideoFeed_remote {
width: 100%; width: 100%;
max-height: 100%; height: 100%;
background-color: #000; background-color: #000;
z-index: 50; z-index: 50;
} }

View File

@ -149,8 +149,8 @@ export default class AuxPanel extends React.Component<IProps, IState> {
const callView = ( const callView = (
<CallViewForRoom <CallViewForRoom
roomId={this.props.room.roomId} roomId={this.props.room.roomId}
onResize={this.props.onResize}
maxVideoHeight={this.props.maxHeight} maxVideoHeight={this.props.maxHeight}
resizeNotifier={this.props.resizeNotifier}
/> />
); );

View File

@ -40,9 +40,6 @@ interface IProps {
// Another ongoing call to display information about // Another ongoing call to display information about
secondaryCall?: MatrixCall, secondaryCall?: MatrixCall,
// maxHeight style attribute for the video panel
maxVideoHeight?: number;
// a callback which is called when the content in the callview changes // a callback which is called when the content in the callview changes
// in a way that is likely to cause a resize. // in a way that is likely to cause a resize.
onResize?: any; onResize?: any;
@ -96,9 +93,6 @@ function exitFullscreen() {
const CONTROLS_HIDE_DELAY = 1000; const CONTROLS_HIDE_DELAY = 1000;
// Height of the header duplicated from CSS because we need to subtract it from our max // Height of the header duplicated from CSS because we need to subtract it from our max
// height to get the max height of the video // height to get the max height of the video
const HEADER_HEIGHT = 44;
const BOTTOM_PADDING = 10;
const BOTTOM_MARGIN_TOP_BOTTOM = 10; // top margin plus bottom margin
const CONTEXT_MENU_VPADDING = 8; // How far the context menu sits above the button (px) const CONTEXT_MENU_VPADDING = 8; // How far the context menu sits above the button (px)
@replaceableComponent("views.voip.CallView") @replaceableComponent("views.voip.CallView")
@ -548,20 +542,9 @@ export default class CallView extends React.Component<IProps, IState> {
localVideoFeed = <VideoFeed type={VideoFeedType.Local} call={this.props.call} />; localVideoFeed = <VideoFeed type={VideoFeedType.Local} call={this.props.call} />;
} }
// if we're fullscreen, we don't want to set a maxHeight on the video element. contentView = <div className={containerClasses} ref={this.contentRef} onMouseMove={this.onMouseMove}>
const maxVideoHeight = getFullScreenElement() || !this.props.maxVideoHeight ? null : (
this.props.maxVideoHeight - (HEADER_HEIGHT + BOTTOM_PADDING + BOTTOM_MARGIN_TOP_BOTTOM)
);
contentView = <div className={containerClasses}
ref={this.contentRef} onMouseMove={this.onMouseMove}
// Put the max height on here too because this div is ended up 4px larger than the content
// and is causing it to scroll, and I am genuinely baffled as to why.
style={{maxHeight: maxVideoHeight}}
>
{onHoldBackground} {onHoldBackground}
<VideoFeed type={VideoFeedType.Remote} call={this.props.call} onResize={this.props.onResize} <VideoFeed type={VideoFeedType.Remote} call={this.props.call} onResize={this.props.onResize} />
maxHeight={maxVideoHeight}
/>
{localVideoFeed} {localVideoFeed}
{holdTransferContent} {holdTransferContent}
{callControls} {callControls}

View File

@ -19,6 +19,8 @@ import React from 'react';
import CallHandler from '../../../CallHandler'; import CallHandler from '../../../CallHandler';
import CallView from './CallView'; import CallView from './CallView';
import dis from '../../../dispatcher/dispatcher'; import dis from '../../../dispatcher/dispatcher';
import {Resizable} from "re-resizable";
import ResizeNotifier from "../../../utils/ResizeNotifier";
import {replaceableComponent} from "../../../utils/replaceableComponent"; import {replaceableComponent} from "../../../utils/replaceableComponent";
interface IProps { interface IProps {
@ -28,9 +30,7 @@ interface IProps {
// maxHeight style attribute for the video panel // maxHeight style attribute for the video panel
maxVideoHeight?: number; maxVideoHeight?: number;
// a callback which is called when the content in the callview changes resizeNotifier: ResizeNotifier,
// in a way that is likely to cause a resize.
onResize?: any;
} }
interface IState { interface IState {
@ -79,11 +79,50 @@ export default class CallViewForRoom extends React.Component<IProps, IState> {
return call; return call;
} }
private onResizeStart = () => {
this.props.resizeNotifier.startResizing();
};
private onResize = () => {
this.props.resizeNotifier.notifyTimelineHeightChanged();
};
private onResizeStop = () => {
this.props.resizeNotifier.stopResizing();
};
public render() { public render() {
if (!this.state.call) return null; if (!this.state.call) return null;
// We subtract 8 as it the margin-bottom of the mx_CallViewForRoom_ResizeWrapper
const maxHeight = this.props.maxVideoHeight - 8;
return <CallView call={this.state.call} pipMode={false} return (
onResize={this.props.onResize} maxVideoHeight={this.props.maxVideoHeight} <div className="mx_CallViewForRoom">
/>; <Resizable
minHeight={380}
maxHeight={maxHeight}
enable={{
top: false,
right: false,
bottom: true,
left: false,
topRight: false,
bottomRight: false,
bottomLeft: false,
topLeft: false,
}}
onResizeStart={this.onResizeStart}
onResize={this.onResize}
onResizeStop={this.onResizeStop}
className="mx_CallViewForRoom_ResizeWrapper"
handleClasses={{bottom: "mx_CallViewForRoom_ResizeHandle"}}
>
<CallView
call={this.state.call}
pipMode={false}
/>
</Resizable>
</div>
);
} }
} }

View File

@ -30,9 +30,6 @@ interface IProps {
type: VideoFeedType, type: VideoFeedType,
// maxHeight style attribute for the video element
maxHeight?: number,
// a callback which is called when the video element is resized // a callback which is called when the video element is resized
// due to a change in video metadata // due to a change in video metadata
onResize?: (e: Event) => void, onResize?: (e: Event) => void,
@ -82,9 +79,6 @@ export default class VideoFeed extends React.Component<IProps> {
), ),
}; };
let videoStyle = {}; return <video className={classnames(videoClasses)} ref={this.vid} />;
if (this.props.maxHeight) videoStyle = { maxHeight: this.props.maxHeight };
return <video className={classnames(videoClasses)} ref={this.vid} style={videoStyle} />;
} }
} }