diff --git a/src/client/components/Video.tsx b/src/client/components/Video.tsx index e9f4e67..aa5fd75 100644 --- a/src/client/components/Video.tsx +++ b/src/client/components/Video.tsx @@ -16,6 +16,7 @@ export interface VideoProps { export default class Video extends React.PureComponent { videoRef = React.createRef() + timeout?: number static defaultProps = { muted: false, @@ -23,8 +24,25 @@ export default class Video extends React.PureComponent { } handleClick: ReactEventHandler = e => { const { onClick, userId } = this.props - this.props.play() - onClick(userId) + if (this.timeout) { + // if the timeout was cancelled, execute click + this.props.play() + onClick(userId) + } + this.timeout = undefined + } + handleMouseDown: ReactEventHandler = e => { + this.timeout = window.setTimeout(this.toggleCover, 300) + } + handleMouseUp: ReactEventHandler = e => { + clearTimeout(this.timeout) + } + toggleCover = () => { + this.timeout = undefined + const v = this.videoRef.current + if (v) { + v.style.objectFit = v.style.objectFit ? '' : 'cover' + } } componentDidMount () { this.componentDidUpdate() @@ -52,6 +70,8 @@ export default class Video extends React.PureComponent { id={`video-${socket.id}`} autoPlay onClick={this.handleClick} + onMouseDown={this.handleMouseDown} + onMouseUp={this.handleMouseUp} onLoadedMetadata={() => this.props.play()} playsInline ref={this.videoRef} diff --git a/src/client/containers/App.test.tsx b/src/client/containers/App.test.tsx index 5b9fc5c..d629b70 100644 --- a/src/client/containers/App.test.tsx +++ b/src/client/containers/App.test.tsx @@ -1,6 +1,7 @@ jest.mock('../actions/CallActions') jest.mock('../socket') jest.mock('../window') +jest.useFakeTimers() import React from 'react' import ReactDOM from 'react-dom' @@ -108,9 +109,14 @@ describe('App', () => { }) describe('video', () => { - it('can be activated', () => { + beforeEach(() => { dispatchSpy.mockReset() + }) + + it('can be activated', () => { const video = node.querySelector('video')! + TestUtils.Simulate.mouseDown(video) + TestUtils.Simulate.mouseUp(video) TestUtils.Simulate.click(video) expect(dispatchSpy.mock.calls[0][0].type).toBe(constants.MEDIA_PLAY) expect(dispatchSpy.mock.calls.slice(1)).toEqual([[{ @@ -118,6 +124,18 @@ describe('App', () => { payload: { userId: constants.ME + '_0' }, }]]) }) + + it('can toggle object-fit to/from cover by long-pressing', () => { + ['cover', ''].forEach(objectFit => { + const video = node.querySelector('video')! + TestUtils.Simulate.mouseDown(video) + jest.runAllTimers() + TestUtils.Simulate.mouseUp(video) + TestUtils.Simulate.click(video) + expect(video.style.objectFit).toBe(objectFit) + expect(dispatchSpy.mock.calls.slice(1)).toEqual([]) + }) + }) }) }) diff --git a/src/scss/_video.scss b/src/scss/_video.scss index d921779..5fa53eb 100644 --- a/src/scss/_video.scss +++ b/src/scss/_video.scss @@ -25,6 +25,10 @@ width: 100%; height: 100%; } + + .video-actions { + display: none; + } } .video-container.active { @@ -43,6 +47,22 @@ video { border-radius: 0; cursor: inherit; + object-fit: contain; + } + + .video-actions { + display: inherit; + position: absolute; + right: 0; + bottom: 0; + padding: 1rem; + font-family: monospace; + user-select: none; + + .action:hover { + cursor: pointer; + color: white; + } } } diff --git a/src/scss/style.scss b/src/scss/style.scss index 33d44e3..1d2de63 100644 --- a/src/scss/style.scss +++ b/src/scss/style.scss @@ -101,8 +101,8 @@ body.call { } input[type="text"] { - font-size: 1rem; - padding: 1rem 1rem 0.75rem; + font-size: 1.2rem; + padding: 1rem 0rem 0.75rem; width: 100%; margin-bottom: 1rem; background: none; @@ -120,9 +120,9 @@ body.call { } input[type="submit"] { - // font-family: $font-monospace; + font-family: $font-monospace; @include button($color-primary, $color-warning); - font-size: 1rem; + font-size: 1.2rem; padding: 1rem 1rem; }