fixed video playback in mobile browser

This commit is contained in:
Roland Osborne 2022-08-27 00:55:59 -07:00
parent 779db5635b
commit 7f5b80a70b
11 changed files with 126 additions and 164 deletions

View File

@ -105,7 +105,7 @@ export const CarouselWrapper = styled.div`
.space { .space {
height: 128px; height: 128px;
padding-left: 32px; padding-left: 4px;
} }
.object { .object {

View File

@ -20,7 +20,9 @@ export function ChannelItem({ item, openChannel }) {
)} )}
{ item.contacts.length === 1 && ( { item.contacts.length === 1 && (
<div class="item"> <div class="item">
<Logo url={item.logo} width={32} height={32} radius={8} /> <div class="avatar">
<Logo url={item.logo} width={32} height={32} radius={8} />
</div>
<div class="details"> <div class="details">
<div class="subject">{ item.subject }</div> <div class="subject">{ item.subject }</div>
<div class="message">{ item.message }</div> <div class="message">{ item.message }</div>

View File

@ -22,6 +22,16 @@ export const ChannelItemWrapper = styled.div`
align-items: center; align-items: center;
min-width: 0; min-width: 0;
.avatar{
display: flex;
align-items: center;
justify-content: center;
border: 1px solid ${Colors.grey};
border-radius: 8px;
font-size: 18px;
flex-shrink: 0;
}
.logo { .logo {
display: flex; display: flex;
align-items: center; align-items: center;

View File

@ -103,15 +103,15 @@ export function TopicItem({ host, topic }) {
<div class={nameClass}>{ name }</div> <div class={nameClass}>{ name }</div>
<div>{ state.created }</div> <div>{ state.created }</div>
</div> </div>
<div class="topic-options">
<Options />
</div>
</div> </div>
{ !state.confirmed && ( { !state.confirmed && (
<div> <div>
<div class="message"> <div class="message">
<Skeleton size={'small'} active={true} /> <Skeleton size={'small'} active={true} />
</div> </div>
<div class="options">
<Options />
</div>
</div> </div>
)} )}
{ state.confirmed && ( { state.confirmed && (
@ -134,9 +134,6 @@ export function TopicItem({ host, topic }) {
<div class="message"> <div class="message">
<Message /> <Message />
</div> </div>
<div class="options">
<Options />
</div>
</div> </div>
)} )}
</TopicItemWrapper> </TopicItemWrapper>

View File

@ -5,10 +5,6 @@ export const TopicItemWrapper = styled.div`
flex-direction: column; flex-direction: column;
width: 100%; width: 100%;
&:hover .options {
visibility: visible;
}
.topic-header { .topic-header {
display: flex; display: flex;
flex-direction: row; flex-direction: row;
@ -18,6 +14,33 @@ export const TopicItemWrapper = styled.div`
padding-top: 8px; padding-top: 8px;
border-top: 1px solid #dddddd; border-top: 1px solid #dddddd;
&:hover .topic-options {
visibility: visible;
}
.topic-options {
position: absolute;
top: 0;
right: 0;
visibility: hidden;
.buttons {
display: flex;
flex-direction: row;
border-radius: 4px;
background-color: #eeeeee;
border: 1px solid #555555;
margin-top: 2px;
.button {
font-size: 14px;
margin-left: 8px;
margin-right: 8px;
cursor: pointer;
}
}
}
.avatar { .avatar {
height: 32px; height: 32px;
width: 32px; width: 32px;
@ -54,29 +77,6 @@ export const TopicItemWrapper = styled.div`
} }
} }
.options {
position: absolute;
top: 0;
right: 0;
visibility: hidden;
.buttons {
display: flex;
flex-direction: row;
border-radius: 4px;
background-color: #eeeeee;
border: 1px solid #555555;
margin-top: 2px;
.button {
font-size: 14px;
margin-left: 8px;
margin-right: 8px;
cursor: pointer;
}
}
}
.asset-placeholder { .asset-placeholder {
width: 128px; width: 128px;
height: 128px; height: 128px;

View File

@ -11,17 +11,15 @@ export function ImageAsset({ thumbUrl, fullUrl }) {
const [dimension, setDimension] = useState({ width: 0, height: 0 }); const [dimension, setDimension] = useState({ width: 0, height: 0 });
const popout = () => { const popout = () => {
if (dimension.width == 0 || dimension.height == 0) { if (dimension.width / dimension.height > window.innerWidth / window.innerHeight) {
actions.setPopout('50%', '50%'); let width = Math.floor(window.innerWidth * 8 / 10);
let height = Math.floor(width * dimension.height / dimension.width);
actions.setPopout(width, height);
} }
else { else {
if (dimension.width / dimension.height > window.innerWidth / window.innerHeight) { let height = Math.floor(window.innerHeight * 8 / 10);
actions.setPopout('80%', 'auto'); let width = Math.floor(height * dimension.width / dimension.height);
} actions.setPopout(width, height);
else {
let width = Math.floor(80 * (dimension.width / dimension.height) * (window.innerHeight / window.innerWidth));
actions.setPopout(width + '%', 'auto');
}
} }
} }
@ -37,13 +35,10 @@ export function ImageAsset({ thumbUrl, fullUrl }) {
</ReactResizeDetector> </ReactResizeDetector>
{ state.display !== 'small' && ( { state.display !== 'small' && (
<div class="viewer"> <div class="viewer">
<div class="overlay" style={{ width: dimension.width, height: dimension.height }}> <div class="overlay" style={{ width: dimension.width, height: dimension.height }}
<div class="expand" onClick={popout}> onClick={popout} />
<ExpandOutlined style={{ fontSize: 24, color: '#eeeeee', cursor: 'pointer' }} /> <Modal centered={true} visible={state.popout} width={state.width + 12} bodyStyle={{ width: '100%', height: 'auto', paddingBottom: 6, paddingTop: 6, paddingLeft: 6, paddingRight: 6, backgroundColor: '#dddddd' }} footer={null} destroyOnClose={true} closable={false} onCancel={actions.clearPopout}>
</div> <img style={{ width: '100%', objectFit: 'contain' }} src={fullUrl} alt="topic image" />
</div>
<Modal visible={state.popout} width={state.width} height={state.height} bodyStyle={{ width: '100%', height: 'auto', paddingBottom: 6, paddingTop: 6, paddingLeft: 6, paddingRight: 6, backgroundColor: '#dddddd' }} footer={null} destroyOnClose={true} closable={false} onCancel={actions.clearPopout}>
<img style={{ width: '100%', objectFit: 'contain' }} src={fullUrl} alt="" />
</Modal> </Modal>
</div> </div>
)} )}

View File

@ -9,15 +9,10 @@ export const ImageAssetWrapper = styled.div`
position: absolute; position: absolute;
} }
.viewer:hover .overlay {
visibility: visible;
}
.overlay { .overlay {
visibility: hidden; cursor: pointer;
position: relative; top: 0;
background-color: black; position: absolute;
opacity: 0.5;
} }
.expand { .expand {

View File

@ -25,7 +25,6 @@ export function useImageAsset() {
updateState({ popout: true, width, height }); updateState({ popout: true, width, height });
}, },
clearPopout: () => { clearPopout: () => {
console.log("CLEAR POPOUT");
updateState({ popout: false }); updateState({ popout: false });
}, },
}; };

View File

@ -1,92 +1,54 @@
import React, { useRef, useEffect, useState } from 'react'; import React, { useRef, useEffect, useState } from 'react';
import { Button, Modal } from 'antd'; import { Button, Modal } from 'antd';
import ReactPlayer from 'react-player'
import ReactResizeDetector from 'react-resize-detector'; import ReactResizeDetector from 'react-resize-detector';
import { SelectOutlined, ExpandOutlined, MinusCircleOutlined, PlayCircleOutlined } from '@ant-design/icons'; import { SelectOutlined, ExpandOutlined, VideoCameraOutlined, MinusCircleOutlined, PlayCircleOutlined } from '@ant-design/icons';
import { VideoAssetWrapper } from './VideoAsset.styled'; import { VideoAssetWrapper } from './VideoAsset.styled';
import { useVideoAsset } from './useVideoAsset.hook';
export function VideoAsset({ thumbUrl, lqUrl, hdUrl }) { export function VideoAsset({ thumbUrl, lqUrl, hdUrl }) {
const [state, setState] = useState({}); const { state, actions } = useVideoAsset();
const player = useRef(null); const [dimension, setDimension] = useState({ width: 0, height: 0 });
const video = useRef(null);
const updateState = (value) => { const activate = () => {
setState((s) => ({ ...s, ...value })); if (dimension.width / dimension.height > window.innerWidth / window.innerHeight) {
} let width = Math.floor(window.innerWidth * 8 / 10);
let height = Math.floor(width * dimension.height / dimension.width);
useEffect(() => { actions.setActive(width, height);
}, [thumbUrl, hdUrl, lqUrl]);
const onPopOut = () => {
if (state.width == 0 || state.height == 0) {
updateState({ popout: true, popWidth: '50%', inline: false, popoutUrl: hdUrl, playing: false, inlineUrl: null });
} }
else { else {
if (state.width / state.height > window.innerWidth / window.innerHeight) { let height = Math.floor(window.innerHeight * 8 / 10);
updateState({ popout: true, popWidth: '70%', inline: false, popoutUrl: hdUrl, playing: false, inlineUrl: null }); let width = Math.floor(height * dimension.width / dimension.height);
} actions.setActive(width, height);
else {
let width = Math.floor(70 * (state.width / state.height) * (window.innerHeight / window.innerWidth));
updateState({ popout: true, popWidth: width + '%', inline: false, popoutUrl: hdUrl, playing: false, inlineUrl: null });
}
} }
} }
const CenterButton = () => {
if (!state.inline) {
return (
<div onClick={() => updateState({ inline: true, inlineUrl: lqUrl, playing: false })}>
<SelectOutlined style={{ fontSize: 48, color: '#eeeeee', cursor: 'pointer' }} />
</div>
)
}
if (state.playing) {
return (
<div onClick={() => updateState({ playing: false })}>
<MinusCircleOutlined style={{ fontSize: 48, color: '#eeeeee', cursor: 'pointer' }} />
</div>
)
}
else {
return (
<div onClick={() => updateState({ playing: true })}>
<PlayCircleOutlined style={{ fontSize: 48, color: '#eeeeee', cursor: 'pointer' }} />
</div>
)
}
}
const Controls = () => {
return (
<div>
<div class="control">
<CenterButton />
</div>
<div class="expand" onClick={() => onPopOut()}>
<ExpandOutlined style={{ fontSize: 24, color: '#eeeeee', cursor: 'pointer' }} />
</div>
</div>
)
}
return ( return (
<VideoAssetWrapper> <VideoAssetWrapper>
<ReactResizeDetector handleWidth={true} handleHeight={true}> <ReactResizeDetector handleWidth={true} handleHeight={true}>
{({ width, height }) => { {({ width, height }) => {
if (width != state.width || height != state.height) { if (width != dimension.width || height != dimension.height) {
updateState({ width, height }); setDimension({ width, height });
} }
return <img style={{ height: '100%', objectFit: 'contain' }} src={thumbUrl} alt="" /> return <img style={{ height: '100%', objectFit: 'contain' }} src={thumbUrl} alt="" />
}} }}
</ReactResizeDetector> </ReactResizeDetector>
<div class="player" style={{ width: state.width, height: state.height }}> <div class="overlay" style={{ width: dimension.width, height: dimension.height }}>
<ReactPlayer ref={player} controls={false} playing={state.playing} { !state.active && (
height="100%" width="100%" url={state.inlineUrl} /> <div onClick={activate}>
<Controls /> <VideoCameraOutlined style={{ fontSize: 32, color: '#eeeeee', cursor: 'pointer' }} />
</div>
)}
{ state.active && state.display === 'small' && (
<video autoplay controls src={hdUrl} width={dimension.width} height={dimension.height} />
)}
{ state.display !== 'small' && (
<Modal centered={true} visible={state.active} width={state.width + 12} bodyStyle={{ paddingBottom: 0, paddingTop: 6, paddingLeft: 6, paddingRight: 6, backgroundColor: '#dddddd' }} footer={null} destroyOnClose={true} closable={false} onCancel={actions.clearActive}>
<video autoplay={true} controls src={hdUrl} width={state.width} height={state.height} />
</Modal>
)}
</div> </div>
<Modal visible={state.popout} width={state.popWidth} bodyStyle={{ paddingBottom: 0, paddingTop: 6, paddingLeft: 6, paddingRight: 6, backgroundColor: '#dddddd' }} footer={null} destroyOnClose={true} closable={false} onCancel={() => { updateState({ popout: false })}}>
<ReactPlayer controls={true} height="100%" width="100%" url={state.popoutUrl} />
</Modal>
</VideoAssetWrapper> </VideoAssetWrapper>
) )
} }

View File

@ -4,46 +4,13 @@ export const VideoAssetWrapper = styled.div`
position: relative; position: relative;
height: 100%; height: 100%;
.playback { .overlay {
top: 0;
position: absolute;
display: flex;
align-items: center;
justify-content: center;
}
.player:hover .control {
visibility: visible;
}
.player:hover .expand {
visibility: visible;
}
.player {
position: absolute; position: absolute;
top: 0; top: 0;
}
.control {
top: 0;
visibility: hidden;
position: absolute;
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
background-color: black;
opacity: 0.5;
}
.expand {
padding-left: 4px;
visibility: hidden;
position: absolute;
bottom: 0;
left: 0; left: 0;
display: flex;
align-items: center;
justify-content: center;
} }
`; `;

View File

@ -0,0 +1,35 @@
import { useContext, useState, useEffect, useRef } from 'react';
import { ViewportContext } from 'context/ViewportContext';
export function useVideoAsset() {
const [state, setState] = useState({
display: null,
width: 0,
height: 0,
active: false,
});
const viewport = useContext(ViewportContext);
const updateState = (value) => {
setState((s) => ({ ...s, ...value }));
}
useEffect(() => {
updateState({ display: viewport.state.display });
}, []);
const actions = {
setActive: (width, height, url) => {
console.log(width, height);
updateState({ active: true, width, height });
},
clearActive: () => {
updateState({ active: false });
},
};
return { state, actions };
}